primal-memory 0.1.0.0 → 0.2.0.0
raw patch · 16 files changed
+3100/−1565 lines, 16 filesdep +QuickCheckdep +doctestdep +template-haskelldep ~basedep ~bytestringdep ~primalPVP ok
version bump matches the API change (PVP)
Dependencies added: QuickCheck, doctest, template-haskell, text
Dependency ranges changed: base, bytestring, primal
API changes (from Hackage documentation)
- Data.Prim.Memory: allocByteCountMem :: (MemAlloc a, MonadPrim s m) => Count Word8 -> m (a s)
- Data.Prim.Memory.ByteArray: ByteArray :: Bytes p -> ByteArray e
- Data.Prim.Memory.ByteArray: Inc :: Pinned
- Data.Prim.Memory.ByteArray: MByteArray :: MBytes p s -> MByteArray e s
- Data.Prim.Memory.ByteArray: Pin :: Pinned
- Data.Prim.Memory.ByteArray: allocAlignedMByteArray :: (MonadPrim s m, Prim e) => Count e -> m (MByteArray 'Pin e s)
- Data.Prim.Memory.ByteArray: allocMByteArray :: forall e p m s. (Typeable p, Prim e, MonadPrim s m) => Size -> m (MByteArray p e s)
- Data.Prim.Memory.ByteArray: allocPinnedMByteArray :: forall e m s. (MonadPrim s m, Prim e) => Size -> m (MByteArray 'Pin e s)
- Data.Prim.Memory.ByteArray: allocUnpinnedMByteArray :: forall e m s. (MonadPrim s m, Prim e) => Size -> m (MByteArray 'Inc e s)
- Data.Prim.Memory.ByteArray: castByteArray :: ByteArray p e' -> ByteArray p e
- Data.Prim.Memory.ByteArray: castMByteArray :: MByteArray p e' s -> MByteArray p e s
- Data.Prim.Memory.ByteArray: copyByteArrayToMByteArray :: (MonadPrim s m, Prim e) => ByteArray p e -> Int -> MByteArray p e s -> Int -> Size -> m ()
- Data.Prim.Memory.ByteArray: data Pinned
- Data.Prim.Memory.ByteArray: freezeMByteArray :: MonadPrim s m => MByteArray p e s -> m (ByteArray p e)
- Data.Prim.Memory.ByteArray: fromBytesByteArray :: Bytes p -> ByteArray p e
- Data.Prim.Memory.ByteArray: fromMBytesMByteArray :: MBytes p s -> MByteArray p e s
- Data.Prim.Memory.ByteArray: getSizeMByteArray :: forall e p m s. (MonadPrim s m, Prim e) => MByteArray p e s -> m Size
- Data.Prim.Memory.ByteArray: instance (Data.Typeable.Internal.Typeable p, Data.Prim.Class.Prim e) => GHC.Exts.IsList (Data.Prim.Memory.ByteArray.ByteArray p e)
- Data.Prim.Memory.ByteArray: instance (GHC.Show.Show e, Data.Prim.Class.Prim e) => GHC.Show.Show (Data.Prim.Memory.ByteArray.ByteArray p e)
- Data.Prim.Memory.ByteArray: instance Control.DeepSeq.NFData (Data.Prim.Memory.ByteArray.ByteArray p e)
- Data.Prim.Memory.ByteArray: instance Control.DeepSeq.NFData (Data.Prim.Memory.ByteArray.MByteArray p e s)
- Data.Prim.Memory.ByteArray: instance Data.Prim.Memory.ForeignPtr.PtrAccess s (Data.Prim.Memory.ByteArray.ByteArray 'Data.Prim.Memory.Bytes.Internal.Pin e)
- Data.Prim.Memory.ByteArray: instance Data.Prim.Memory.ForeignPtr.PtrAccess s (Data.Prim.Memory.ByteArray.MByteArray 'Data.Prim.Memory.Bytes.Internal.Pin e s)
- Data.Prim.Memory.ByteArray: instance Data.Prim.Memory.Internal.MemRead (Data.Prim.Memory.ByteArray.ByteArray p e)
- Data.Prim.Memory.ByteArray: instance Data.Prim.Memory.Internal.MemWrite (Data.Prim.Memory.ByteArray.MByteArray p e)
- Data.Prim.Memory.ByteArray: instance Data.Typeable.Internal.Typeable p => Data.Prim.Memory.Internal.MemAlloc (Data.Prim.Memory.ByteArray.MByteArray p e)
- Data.Prim.Memory.ByteArray: instance Data.Typeable.Internal.Typeable p => Data.String.IsString (Data.Prim.Memory.ByteArray.ByteArray p GHC.Types.Char)
- Data.Prim.Memory.ByteArray: instance Data.Typeable.Internal.Typeable p => GHC.Base.Monoid (Data.Prim.Memory.ByteArray.ByteArray p e)
- Data.Prim.Memory.ByteArray: instance Data.Typeable.Internal.Typeable p => GHC.Base.Semigroup (Data.Prim.Memory.ByteArray.ByteArray p e)
- Data.Prim.Memory.ByteArray: isPinnedByteArray :: ByteArray p e -> Bool
- Data.Prim.Memory.ByteArray: isPinnedMByteArray :: MByteArray p e s -> Bool
- Data.Prim.Memory.ByteArray: moveMByteArrayToMByteArray :: forall e p m s. (MonadPrim s m, Prim e) => MByteArray p e s -> Int -> MByteArray p e s -> Int -> Size -> m ()
- Data.Prim.Memory.ByteArray: newtype ByteArray (p :: Pinned) e
- Data.Prim.Memory.ByteArray: newtype MByteArray (p :: Pinned) e s
- Data.Prim.Memory.ByteArray: readMByteArray :: (MonadPrim s m, Prim e) => MByteArray p e s -> Int -> m e
- Data.Prim.Memory.ByteArray: reallocMByteArray :: forall e p m s. (MonadPrim s m, Typeable p, Prim e) => MByteArray p e s -> Size -> m (MByteArray p e s)
- Data.Prim.Memory.ByteArray: resizeMByteArray :: forall e p m s. (MonadPrim s m, Prim e) => MByteArray p e s -> Size -> m (MByteArray 'Inc e s)
- Data.Prim.Memory.ByteArray: setMByteArray :: (MonadPrim s m, Prim e) => MByteArray p e s -> Int -> Size -> e -> m ()
- Data.Prim.Memory.ByteArray: shrinkMByteArray :: forall e p m s. (MonadPrim s m, Prim e) => MByteArray p e s -> Size -> m ()
- Data.Prim.Memory.ByteArray: sizeByteArray :: forall e p. Prim e => ByteArray p e -> Size
- Data.Prim.Memory.ByteArray: thawByteArray :: MonadPrim s m => ByteArray p e -> m (MByteArray p e s)
- Data.Prim.Memory.ByteArray: toBytesByteArray :: ByteArray p e -> Bytes p
- Data.Prim.Memory.ByteArray: toMBytesMByteArray :: MByteArray p e s -> MBytes p s
- Data.Prim.Memory.ByteArray: writeMByteArray :: (MonadPrim s m, Prim e) => MByteArray p e s -> Int -> e -> m ()
- Data.Prim.Memory.Internal: Bytes :: ByteArray# -> Bytes
- Data.Prim.Memory.Internal: Inc :: Pinned
- Data.Prim.Memory.Internal: MBytes :: MutableByteArray# s -> MBytes s
- Data.Prim.Memory.Internal: MMemView :: {-# UNPACK #-} !Off Word8 -> {-# UNPACK #-} !Count Word8 -> !a s -> MMemView a s
- Data.Prim.Memory.Internal: MemState :: a -> MemState a s
- Data.Prim.Memory.Internal: MemView :: {-# UNPACK #-} !Off Word8 -> {-# UNPACK #-} !Count Word8 -> !a -> MemView a
- Data.Prim.Memory.Internal: Pin :: Pinned
- Data.Prim.Memory.Internal: [mmvCount] :: MMemView a s -> {-# UNPACK #-} !Count Word8
- Data.Prim.Memory.Internal: [mmvMem] :: MMemView a s -> !a s
- Data.Prim.Memory.Internal: [mmvOffset] :: MMemView a s -> {-# UNPACK #-} !Off Word8
- Data.Prim.Memory.Internal: [mvCount] :: MemView a -> {-# UNPACK #-} !Count Word8
- Data.Prim.Memory.Internal: [mvMem] :: MemView a -> !a
- Data.Prim.Memory.Internal: [mvOffset] :: MemView a -> {-# UNPACK #-} !Off Word8
- Data.Prim.Memory.Internal: [unMemState] :: MemState a s -> a
- Data.Prim.Memory.Internal: allocByteCountMem :: (MemAlloc a, MonadPrim s m) => Count Word8 -> m (a s)
- Data.Prim.Memory.Internal: allocMem :: (MemAlloc a, MonadPrim s m, Prim e) => Count e -> m (a s)
- Data.Prim.Memory.Internal: allocZeroMem :: (MemAlloc a, MonadPrim s m, Prim e) => Count e -> m (a s)
- Data.Prim.Memory.Internal: appendMem :: (MemRead r1, MemRead r2, MemAlloc a) => r1 -> r2 -> FrozenMem a
- Data.Prim.Memory.Internal: byteCountMem :: MemRead r => r -> Count Word8
- Data.Prim.Memory.Internal: class (MemRead (FrozenMem a), MemWrite a) => MemAlloc a where {
- Data.Prim.Memory.Internal: class MemRead r
- Data.Prim.Memory.Internal: class MemWrite w
- Data.Prim.Memory.Internal: clone :: (MemAlloc r, MonadPrim s m) => r s -> m (r s)
- Data.Prim.Memory.Internal: compareByteOffMem :: (MemRead r, MemRead r', Prim e) => r' -> Off Word8 -> r -> Off Word8 -> Count e -> Ordering
- Data.Prim.Memory.Internal: compareByteOffToBytesMem :: (MemRead r, MonadPrim s m, Prim e) => r -> Off Word8 -> Bytes p -> Off Word8 -> Count e -> m Ordering
- Data.Prim.Memory.Internal: compareByteOffToPtrMem :: (MemRead r, MonadPrim s m, Prim e) => r -> Off Word8 -> Ptr e -> Off Word8 -> Count e -> m Ordering
- Data.Prim.Memory.Internal: compareMem :: (MemRead r1, MemRead r2, Prim e) => r1 -> Off e -> r2 -> Off e -> Count e -> Ordering
- Data.Prim.Memory.Internal: concatMem :: (MemRead r, MemAlloc a) => [r] -> FrozenMem a
- Data.Prim.Memory.Internal: convertMem :: (MemRead r, MemAlloc a) => r -> FrozenMem a
- Data.Prim.Memory.Internal: copyByteOffMem :: (MemWrite w, MonadPrim s m, MemRead r, Prim e) => r -> Off Word8 -> w s -> Off Word8 -> Count e -> m ()
- Data.Prim.Memory.Internal: copyByteOffToMBytesMem :: (MemRead r, MonadPrim s m, Prim e) => r -> Off Word8 -> MBytes p s -> Off Word8 -> Count e -> m ()
- Data.Prim.Memory.Internal: copyByteOffToPtrMem :: (MemRead r, MonadPrim s m, Prim e) => r -> Off Word8 -> Ptr e -> Off Word8 -> Count e -> m ()
- Data.Prim.Memory.Internal: copyMem :: (MonadPrim s m, MemRead r, MemWrite w, Prim e) => r -> Off e -> w s -> Off e -> Count e -> m ()
- Data.Prim.Memory.Internal: countMem :: forall e r. (MemRead r, Prim e) => r -> Count e
- Data.Prim.Memory.Internal: countRemMem :: forall e r. (MemRead r, Prim e) => r -> (Count e, Count Word8)
- Data.Prim.Memory.Internal: createMemST :: (MemAlloc a, Prim e) => Count e -> (forall s. a s -> ST s b) -> (b, FrozenMem a)
- Data.Prim.Memory.Internal: createMemST_ :: (MemAlloc a, Prim e) => Count e -> (forall s. a s -> ST s b) -> FrozenMem a
- Data.Prim.Memory.Internal: createZeroMemST :: (MemAlloc a, Prim e) => Count e -> (forall s. a s -> ST s b) -> (b, FrozenMem a)
- Data.Prim.Memory.Internal: createZeroMemST_ :: (MemAlloc a, Prim e) => Count e -> (forall s. a s -> ST s b) -> FrozenMem a
- Data.Prim.Memory.Internal: cycleMemN :: (MemAlloc a, MemRead r) => Int -> r -> FrozenMem a
- Data.Prim.Memory.Internal: data Bytes (p :: Pinned)
- Data.Prim.Memory.Internal: data MBytes (p :: Pinned) s
- Data.Prim.Memory.Internal: data MMemView a s
- Data.Prim.Memory.Internal: data MemView a
- Data.Prim.Memory.Internal: data Pinned
- Data.Prim.Memory.Internal: defaultResizeMem :: (Prim e, MemAlloc a, MonadPrim s m) => a s -> Count e -> m (a s)
- Data.Prim.Memory.Internal: emptyMem :: MemAlloc a => FrozenMem a
- Data.Prim.Memory.Internal: eqMem :: (MemRead r1, MemRead r2) => r1 -> r2 -> Bool
- Data.Prim.Memory.Internal: foldrCountMem :: (MemRead r, Prim e) => Count e -> (e -> b -> b) -> b -> r -> b
- Data.Prim.Memory.Internal: forByteOffMemM_ :: (MemRead r, MonadPrim s m, Prim e) => r -> Off Word8 -> Count e -> (Off Word8 -> e -> m b) -> m (Off Word8)
- Data.Prim.Memory.Internal: freezeCloneMem :: (MemAlloc a, MonadPrim s m) => a s -> m (FrozenMem a)
- Data.Prim.Memory.Internal: freezeCopyMem :: (MemAlloc a, MonadPrim s m, Prim e) => a s -> Off e -> Count e -> m (FrozenMem a)
- Data.Prim.Memory.Internal: freezeMem :: (MemAlloc a, MonadPrim s m) => a s -> m (FrozenMem a)
- Data.Prim.Memory.Internal: fromByteListMem :: MemAlloc a => [Word8] -> FrozenMem a
- Data.Prim.Memory.Internal: fromListMem :: (MemAlloc a, Prim e) => [e] -> FrozenMem a
- Data.Prim.Memory.Internal: fromListMemN :: (MemAlloc a, Prim e) => Count e -> [e] -> (Ordering, FrozenMem a)
- Data.Prim.Memory.Internal: fromListMemN_ :: (MemAlloc a, Prim e) => Count e -> [e] -> FrozenMem a
- Data.Prim.Memory.Internal: getByteCountMem :: (MemAlloc a, MonadPrim s m) => a s -> m (Count Word8)
- Data.Prim.Memory.Internal: getCountMem :: (MemAlloc r, MonadPrim s m, Prim e) => r s -> m (Count e)
- Data.Prim.Memory.Internal: getCountRemMem :: (MemAlloc r, MonadPrim s m, Prim e) => r s -> m (Count e, Count Word8)
- Data.Prim.Memory.Internal: indexByteOffMem :: (MemRead r, Prim e) => r -> Off Word8 -> e
- Data.Prim.Memory.Internal: indexOffMem :: (MemRead r, Prim e) => r -> Off e -> e
- Data.Prim.Memory.Internal: instance Data.Prim.Memory.Internal.MemAlloc Data.Prim.Memory.ByteString.MByteString
- Data.Prim.Memory.Internal: instance Data.Prim.Memory.Internal.MemRead (Data.Prim.Memory.Bytes.Internal.Bytes p)
- Data.Prim.Memory.Internal: instance Data.Prim.Memory.Internal.MemRead Data.ByteString.Internal.ByteString
- Data.Prim.Memory.Internal: instance Data.Prim.Memory.Internal.MemRead Data.ByteString.Short.Internal.ShortByteString
- Data.Prim.Memory.Internal: instance Data.Prim.Memory.Internal.MemWrite (Data.Prim.Memory.Bytes.Internal.MBytes p)
- Data.Prim.Memory.Internal: instance Data.Prim.Memory.Internal.MemWrite (Data.Prim.Memory.Internal.MemState (GHC.ForeignPtr.ForeignPtr a))
- Data.Prim.Memory.Internal: instance Data.Prim.Memory.Internal.MemWrite Data.Prim.Memory.ByteString.MByteString
- Data.Prim.Memory.Internal: instance Data.Typeable.Internal.Typeable p => Data.Prim.Memory.Internal.MemAlloc (Data.Prim.Memory.Bytes.Internal.MBytes p)
- Data.Prim.Memory.Internal: instance Data.Typeable.Internal.Typeable p => GHC.Base.Monoid (Data.Prim.Memory.Bytes.Internal.Bytes p)
- Data.Prim.Memory.Internal: instance Data.Typeable.Internal.Typeable p => GHC.Base.Semigroup (Data.Prim.Memory.Bytes.Internal.Bytes p)
- Data.Prim.Memory.Internal: instance Data.Typeable.Internal.Typeable p => GHC.Exts.IsList (Data.Prim.Memory.Bytes.Internal.Bytes p)
- Data.Prim.Memory.Internal: instance GHC.Classes.Eq (Data.Prim.Memory.Bytes.Internal.Bytes p)
- Data.Prim.Memory.Internal: instance GHC.Classes.Ord (Data.Prim.Memory.Bytes.Internal.Bytes p)
- Data.Prim.Memory.Internal: instance GHC.Show.Show (Data.Prim.Memory.Bytes.Internal.Bytes p)
- Data.Prim.Memory.Internal: izipWithByteOffMemM_ :: (MemRead r1, MemRead r2, MonadPrim s m, Prim e) => r1 -> Off Word8 -> r2 -> Off Word8 -> Count e -> (Off Word8 -> e -> Off Word8 -> e -> m b) -> m (Off Word8)
- Data.Prim.Memory.Internal: izipWithOffMemM_ :: (MemRead r1, MemRead r2, MonadPrim s m, Prim e1, Prim e2) => r1 -> Off e1 -> r2 -> Off e2 -> Int -> (Off e1 -> e1 -> Off e2 -> e2 -> m b) -> m ()
- Data.Prim.Memory.Internal: loadListMem :: (MonadPrim s m, MemAlloc r, Prim e) => [e] -> r s -> m Ordering
- Data.Prim.Memory.Internal: loadListMemN :: (MemWrite r, MonadPrim s m, Prim e) => Count e -> Count Word8 -> [e] -> r s -> m Ordering
- Data.Prim.Memory.Internal: loadListMemN_ :: (MemWrite r, MonadPrim s m, Prim e) => Count e -> [e] -> r s -> m ()
- Data.Prim.Memory.Internal: loadListMem_ :: (MonadPrim s m, MemAlloc r, Prim e) => [e] -> r s -> m ()
- Data.Prim.Memory.Internal: loopShortM :: Monad m => Int -> (Int -> a -> Bool) -> (Int -> Int) -> a -> (Int -> a -> m a) -> m a
- Data.Prim.Memory.Internal: loopShortM' :: Monad m => Int -> (Int -> a -> m Bool) -> (Int -> Int) -> a -> (Int -> a -> m a) -> m a
- Data.Prim.Memory.Internal: mapByteMem :: (MemRead r, MemAlloc a, Prim e) => (Word8 -> e) -> r -> FrozenMem a
- Data.Prim.Memory.Internal: mapByteMemM :: (MemRead r, MemAlloc a, MonadPrim s m, Prim e) => (Word8 -> m e) -> r -> m (FrozenMem a)
- Data.Prim.Memory.Internal: mapByteOffMem :: (MemRead r, MemAlloc a, Prim e) => (Off Word8 -> Word8 -> e) -> r -> FrozenMem a
- Data.Prim.Memory.Internal: mapByteOffMemM :: (MemRead r, MemAlloc a, MonadPrim s m, Prim e) => (Off Word8 -> Word8 -> m e) -> r -> m (FrozenMem a)
- Data.Prim.Memory.Internal: modifyFetchNewMem :: (MemWrite w, MonadPrim s m, Prim b) => w s -> Off b -> (b -> b) -> m b
- Data.Prim.Memory.Internal: modifyFetchNewMemM :: (MemWrite w, MonadPrim s m, Prim b) => w s -> Off b -> (b -> m b) -> m b
- Data.Prim.Memory.Internal: modifyFetchOldMem :: (MemWrite w, MonadPrim s m, Prim b) => w s -> Off b -> (b -> b) -> m b
- Data.Prim.Memory.Internal: modifyFetchOldMemM :: (MemWrite w, MonadPrim s m, Prim b) => w s -> Off b -> (b -> m b) -> m b
- Data.Prim.Memory.Internal: moveByteOffMem :: (MemWrite w, MonadPrim s m, MemWrite w', Prim e) => w' s -> Off Word8 -> w s -> Off Word8 -> Count e -> m ()
- Data.Prim.Memory.Internal: moveByteOffToMBytesMem :: (MemWrite w, MonadPrim s m, Prim e) => w s -> Off Word8 -> MBytes p s -> Off Word8 -> Count e -> m ()
- Data.Prim.Memory.Internal: moveByteOffToPtrMem :: (MemWrite w, MonadPrim s m, Prim e) => w s -> Off Word8 -> Ptr e -> Off Word8 -> Count e -> m ()
- Data.Prim.Memory.Internal: moveMem :: (MonadPrim s m, MemWrite w1, MemWrite w2, Prim e) => w1 s -> Off e -> w2 s -> Off e -> Count e -> m ()
- Data.Prim.Memory.Internal: newtype MemState a s
- Data.Prim.Memory.Internal: readByteOffMem :: (MemWrite w, MonadPrim s m, Prim e) => w s -> Off Word8 -> m e
- Data.Prim.Memory.Internal: readOffMem :: (MemWrite w, MonadPrim s m, Prim e) => w s -> Off e -> m e
- Data.Prim.Memory.Internal: resizeMem :: (MemAlloc a, MonadPrim s m, Prim e) => a s -> Count e -> m (a s)
- Data.Prim.Memory.Internal: setMem :: (MemWrite w, MonadPrim s m, Prim e) => w s -> Off e -> Count e -> e -> m ()
- Data.Prim.Memory.Internal: showsHexMem :: MemRead r => r -> [ShowS]
- Data.Prim.Memory.Internal: singletonMem :: forall e a. (MemAlloc a, Prim e) => e -> FrozenMem a
- Data.Prim.Memory.Internal: thawCloneMem :: (MemRead r, MemAlloc a, MonadPrim s m) => r -> m (a s)
- Data.Prim.Memory.Internal: thawCopyMem :: (MemRead r, MemAlloc a, MonadPrim s m, Prim e) => r -> Off e -> Count e -> m (a s)
- Data.Prim.Memory.Internal: thawMem :: (MemAlloc a, MonadPrim s m) => FrozenMem a -> m (a s)
- Data.Prim.Memory.Internal: toByteListMem :: MemAlloc a => FrozenMem a -> [Word8]
- Data.Prim.Memory.Internal: toListMem :: (MemRead r, Prim e) => r -> [e]
- Data.Prim.Memory.Internal: toListSlackMem :: forall e r. (MemRead r, Prim e) => r -> ([e], [Word8])
- Data.Prim.Memory.Internal: type family FrozenMem a = (fa :: Type) | fa -> a;
- Data.Prim.Memory.Internal: withScrubbedMem :: (MonadUnliftPrim RW m, Prim e, MemAlloc mem) => Count e -> (mem RW -> m a) -> m a
- Data.Prim.Memory.Internal: writeByteOffMem :: (MemWrite w, MonadPrim s m, Prim e) => w s -> Off Word8 -> e -> m ()
- Data.Prim.Memory.Internal: writeOffMem :: (MemWrite w, MonadPrim s m, Prim e) => w s -> Off e -> e -> m ()
- Data.Prim.Memory.Internal: }
+ Data.Prim.Memory: -- <tt>ma <a>-</a> FrozeMem ma</tt> will always uniquely identify each
+ Data.Prim.Memory: -- inference.
+ Data.Prim.Memory: -- other, which is an extremely useful property when it comes to type
+ Data.Prim.Memory: -- states of memory region are in one-to-one correspondence, therefore
+ Data.Prim.Memory: -- | Memory region in the immutable state. Types for frozen and thawed
+ Data.Prim.Memory: cloneMem :: forall ma. MemAlloc ma => FrozenMem ma -> FrozenMem ma
+ Data.Prim.Memory: compareByteOffToBytesMem :: (MemRead mr, Prim e) => mr -> Off Word8 -> Bytes p -> Off Word8 -> Count e -> Ordering
+ Data.Prim.Memory: compareByteOffToPtrMem :: (MemRead mr, MonadPrim s m, Prim e) => mr -> Off Word8 -> Ptr e -> Off Word8 -> Count e -> m Ordering
+ Data.Prim.Memory: copyByteOffToMBytesMem :: (MemRead mr, MonadPrim s m, Prim e) => mr -> Off Word8 -> MBytes p s -> Off Word8 -> Count e -> m ()
+ Data.Prim.Memory: copyByteOffToPtrMem :: (MemRead mr, MonadPrim s m, Prim e) => mr -> Off Word8 -> Ptr e -> Off Word8 -> Count e -> m ()
+ Data.Prim.Memory: fromListZeroMemN :: forall e ma. (Prim e, MemAlloc ma) => Count e -> [e] -> (Either [e] (Count e), FrozenMem ma)
+ Data.Prim.Memory: fromListZeroMemN_ :: forall e ma. (Prim e, MemAlloc ma) => Count e -> [e] -> FrozenMem ma
+ Data.Prim.Memory: loadListByteOffMem :: (MemAlloc ma, MonadPrim s m, Prim e) => [e] -> ma s -> Off Word8 -> m ([e], Count e)
+ Data.Prim.Memory: loadListByteOffMemN :: (MemWrite mw, MonadPrim s m, Prim e) => Count e -> [e] -> mw s -> Off Word8 -> m ([e], Count e)
+ Data.Prim.Memory: loadListOffMem :: forall e ma m s. (Prim e, MemAlloc ma, MonadPrim s m) => [e] -> ma s -> Off e -> m ([e], Count e)
+ Data.Prim.Memory: loadListOffMemN :: (MemWrite mw, MonadPrim s m, Prim e) => Count e -> [e] -> mw s -> Off e -> m ([e], Count e)
+ Data.Prim.Memory: moveByteOffToMBytesMem :: (MemWrite mw, MonadPrim s m, Prim e) => mw s -> Off Word8 -> MBytes p s -> Off Word8 -> Count e -> m ()
+ Data.Prim.Memory: moveByteOffToPtrMem :: (MemWrite mw, MonadPrim s m, Prim e) => mw s -> Off Word8 -> Ptr e -> Off Word8 -> Count e -> m ()
+ Data.Prim.Memory: resizeMem :: (MemAlloc ma, MonadPrim s m, Prim e) => ma s -> Count e -> m (ma s)
+ Data.Prim.Memory: showsHexMem :: MemRead mr => mr -> [ShowS]
+ Data.Prim.Memory: withScrubbedMem :: forall e ma m a. (MonadUnliftPrim RW m, Prim e, MemAlloc ma, PtrAccess RW (ma RW)) => Count e -> (ma RW -> m a) -> m a
+ Data.Prim.Memory.Bytes: toInconclusiveBytes :: Bytes p -> Bytes 'Inc
+ Data.Prim.Memory.Bytes: toInconclusiveMBytes :: MBytes p e -> MBytes 'Inc e
+ Data.Prim.Memory.PrimArray: Inc :: Pinned
+ Data.Prim.Memory.PrimArray: MPrimArray :: MBytes p s -> MPrimArray e s
+ Data.Prim.Memory.PrimArray: Pin :: Pinned
+ Data.Prim.Memory.PrimArray: PrimArray :: Bytes p -> PrimArray e
+ Data.Prim.Memory.PrimArray: allocAlignedMPrimArray :: (MonadPrim s m, Prim e) => Count e -> m (MPrimArray 'Pin e s)
+ Data.Prim.Memory.PrimArray: allocMPrimArray :: forall e p m s. (Typeable p, Prim e, MonadPrim s m) => Size -> m (MPrimArray p e s)
+ Data.Prim.Memory.PrimArray: allocPinnedMPrimArray :: forall e m s. (MonadPrim s m, Prim e) => Size -> m (MPrimArray 'Pin e s)
+ Data.Prim.Memory.PrimArray: allocUnpinnedMPrimArray :: forall e m s. (MonadPrim s m, Prim e) => Size -> m (MPrimArray 'Inc e s)
+ Data.Prim.Memory.PrimArray: castMPrimArray :: MPrimArray p e' s -> MPrimArray p e s
+ Data.Prim.Memory.PrimArray: castPrimArray :: PrimArray p e' -> PrimArray p e
+ Data.Prim.Memory.PrimArray: copyPrimArrayToMPrimArray :: forall e p m s. (MonadPrim s m, Prim e) => PrimArray p e -> Int -> MPrimArray p e s -> Int -> Size -> m ()
+ Data.Prim.Memory.PrimArray: data Pinned
+ Data.Prim.Memory.PrimArray: freezeMPrimArray :: MonadPrim s m => MPrimArray p e s -> m (PrimArray p e)
+ Data.Prim.Memory.PrimArray: fromBytesPrimArray :: Bytes p -> PrimArray p e
+ Data.Prim.Memory.PrimArray: fromMBytesMPrimArray :: MBytes p s -> MPrimArray p e s
+ Data.Prim.Memory.PrimArray: getSizeMPrimArray :: forall e p m s. (MonadPrim s m, Prim e) => MPrimArray p e s -> m Size
+ Data.Prim.Memory.PrimArray: instance (Data.Typeable.Internal.Typeable p, Data.Prim.Class.Prim e) => GHC.Exts.IsList (Data.Prim.Memory.PrimArray.PrimArray p e)
+ Data.Prim.Memory.PrimArray: instance (GHC.Show.Show e, Data.Prim.Class.Prim e) => GHC.Show.Show (Data.Prim.Memory.PrimArray.PrimArray p e)
+ Data.Prim.Memory.PrimArray: instance Control.DeepSeq.NFData (Data.Prim.Memory.PrimArray.MPrimArray p e s)
+ Data.Prim.Memory.PrimArray: instance Control.DeepSeq.NFData (Data.Prim.Memory.PrimArray.PrimArray p e)
+ Data.Prim.Memory.PrimArray: instance Data.Prim.Memory.ForeignPtr.PtrAccess s (Data.Prim.Memory.PrimArray.MPrimArray 'Data.Prim.Memory.Bytes.Internal.Pin e s)
+ Data.Prim.Memory.PrimArray: instance Data.Prim.Memory.ForeignPtr.PtrAccess s (Data.Prim.Memory.PrimArray.PrimArray 'Data.Prim.Memory.Bytes.Internal.Pin e)
+ Data.Prim.Memory.PrimArray: instance Data.Prim.Memory.Internal.MemRead (Data.Prim.Memory.PrimArray.PrimArray p e)
+ Data.Prim.Memory.PrimArray: instance Data.Prim.Memory.Internal.MemWrite (Data.Prim.Memory.PrimArray.MPrimArray p e)
+ Data.Prim.Memory.PrimArray: instance Data.Typeable.Internal.Typeable p => Data.Prim.Memory.Internal.MemAlloc (Data.Prim.Memory.PrimArray.MPrimArray p e)
+ Data.Prim.Memory.PrimArray: instance Data.Typeable.Internal.Typeable p => Data.String.IsString (Data.Prim.Memory.PrimArray.PrimArray p GHC.Types.Char)
+ Data.Prim.Memory.PrimArray: instance Data.Typeable.Internal.Typeable p => GHC.Base.Monoid (Data.Prim.Memory.PrimArray.PrimArray p e)
+ Data.Prim.Memory.PrimArray: instance Data.Typeable.Internal.Typeable p => GHC.Base.Semigroup (Data.Prim.Memory.PrimArray.PrimArray p e)
+ Data.Prim.Memory.PrimArray: isPinnedMPrimArray :: MPrimArray p e s -> Bool
+ Data.Prim.Memory.PrimArray: isPinnedPrimArray :: PrimArray p e -> Bool
+ Data.Prim.Memory.PrimArray: moveMPrimArrayToMPrimArray :: forall e p m s. (MonadPrim s m, Prim e) => MPrimArray p e s -> Int -> MPrimArray p e s -> Int -> Size -> m ()
+ Data.Prim.Memory.PrimArray: newtype MPrimArray (p :: Pinned) e s
+ Data.Prim.Memory.PrimArray: newtype PrimArray (p :: Pinned) e
+ Data.Prim.Memory.PrimArray: readMPrimArray :: (MonadPrim s m, Prim e) => MPrimArray p e s -> Int -> m e
+ Data.Prim.Memory.PrimArray: reallocMPrimArray :: forall e p m s. (MonadPrim s m, Typeable p, Prim e) => MPrimArray p e s -> Size -> m (MPrimArray p e s)
+ Data.Prim.Memory.PrimArray: resizeMPrimArray :: forall e p m s. (MonadPrim s m, Prim e) => MPrimArray p e s -> Size -> m (MPrimArray 'Inc e s)
+ Data.Prim.Memory.PrimArray: setMPrimArray :: forall e p m s. (MonadPrim s m, Prim e) => MPrimArray p e s -> Int -> Size -> e -> m ()
+ Data.Prim.Memory.PrimArray: shrinkMPrimArray :: forall e p m s. (MonadPrim s m, Prim e) => MPrimArray p e s -> Size -> m ()
+ Data.Prim.Memory.PrimArray: sizePrimArray :: forall e p. Prim e => PrimArray p e -> Size
+ Data.Prim.Memory.PrimArray: thawPrimArray :: MonadPrim s m => PrimArray p e -> m (MPrimArray p e s)
+ Data.Prim.Memory.PrimArray: toBytesPrimArray :: PrimArray p e -> Bytes p
+ Data.Prim.Memory.PrimArray: toMBytesMPrimArray :: MPrimArray p e s -> MBytes p s
+ Data.Prim.Memory.PrimArray: writeMPrimArray :: (MonadPrim s m, Prim e) => MPrimArray p e s -> Int -> e -> m ()
+ Data.Prim.Memory.Text: Array :: ByteArray# -> Array
+ Data.Prim.Memory.Text: MArray :: MutableByteArray# s -> MArray s
+ Data.Prim.Memory.Text: MText :: {-# UNPACK #-} !MArray s -> {-# UNPACK #-} !Int -> {-# UNPACK #-} !Int -> MText s
+ Data.Prim.Memory.Text: Text :: {-# UNPACK #-} !Array -> {-# UNPACK #-} !Int -> {-# UNPACK #-} !Int -> Text
+ Data.Prim.Memory.Text: [aBA] :: Array -> ByteArray#
+ Data.Prim.Memory.Text: [maBA] :: MArray s -> MutableByteArray# s
+ Data.Prim.Memory.Text: data Array
+ Data.Prim.Memory.Text: data MArray s
+ Data.Prim.Memory.Text: data MText s
+ Data.Prim.Memory.Text: data Text
+ Data.Prim.Memory.Text: fromBytesArray :: Bytes p -> Array
+ Data.Prim.Memory.Text: fromMBytesMArray :: MBytes p s -> MArray s
+ Data.Prim.Memory.Text: toBytesArray :: Array -> Bytes 'Inc
+ Data.Prim.Memory.Text: toMBytesMArray :: MArray s -> MBytes 'Inc s
- Data.Prim.Memory: allocMem :: (MemAlloc a, MonadPrim s m, Prim e) => Count e -> m (a s)
+ Data.Prim.Memory: allocMem :: (MemAlloc ma, Prim e, MonadPrim s m) => Count e -> m (ma s)
- Data.Prim.Memory: allocZeroMem :: (MemAlloc a, MonadPrim s m, Prim e) => Count e -> m (a s)
+ Data.Prim.Memory: allocZeroMem :: forall e ma m s. (MemAlloc ma, MonadPrim s m, Prim e) => Count e -> m (ma s)
- Data.Prim.Memory: byteCountMem :: MemRead r => r -> Count Word8
+ Data.Prim.Memory: byteCountMem :: MemRead mr => mr -> Count Word8
- Data.Prim.Memory: class (MemRead (FrozenMem a), MemWrite a) => MemAlloc a where {
+ Data.Prim.Memory: class (MemRead (FrozenMem ma), MemWrite ma) => MemAlloc ma where {
- Data.Prim.Memory: class MemRead r
+ Data.Prim.Memory: class MemRead mr
- Data.Prim.Memory: class MemWrite w
+ Data.Prim.Memory: class MemWrite mw
- Data.Prim.Memory: compareByteOffMem :: (MemRead r, MemRead r', Prim e) => r' -> Off Word8 -> r -> Off Word8 -> Count e -> Ordering
+ Data.Prim.Memory: compareByteOffMem :: (MemRead mr, MemRead mr', Prim e) => mr' -> Off Word8 -> mr -> Off Word8 -> Count e -> Ordering
- Data.Prim.Memory: compareMem :: (MemRead r1, MemRead r2, Prim e) => r1 -> Off e -> r2 -> Off e -> Count e -> Ordering
+ Data.Prim.Memory: compareMem :: forall e mr1 mr2. (MemRead mr1, MemRead mr2, Prim e) => mr1 -> Off e -> mr2 -> Off e -> Count e -> Ordering
- Data.Prim.Memory: convertMem :: (MemRead r, MemAlloc a) => r -> FrozenMem a
+ Data.Prim.Memory: convertMem :: (MemRead mr, MemAlloc ma) => mr -> FrozenMem ma
- Data.Prim.Memory: copyByteOffMem :: (MemWrite w, MonadPrim s m, MemRead r, Prim e) => r -> Off Word8 -> w s -> Off Word8 -> Count e -> m ()
+ Data.Prim.Memory: copyByteOffMem :: (MemWrite mw, MonadPrim s m, MemRead mr, Prim e) => mr -> Off Word8 -> mw s -> Off Word8 -> Count e -> m ()
- Data.Prim.Memory: copyMem :: (MonadPrim s m, MemRead r, MemWrite w, Prim e) => r -> Off e -> w s -> Off e -> Count e -> m ()
+ Data.Prim.Memory: copyMem :: (MonadPrim s m, MemRead mr, MemWrite mw, Prim e) => mr -> Off e -> mw s -> Off e -> Count e -> m ()
- Data.Prim.Memory: countMem :: forall e r. (MemRead r, Prim e) => r -> Count e
+ Data.Prim.Memory: countMem :: forall e mr. (MemRead mr, Prim e) => mr -> Count e
- Data.Prim.Memory: countRemMem :: forall e r. (MemRead r, Prim e) => r -> (Count e, Count Word8)
+ Data.Prim.Memory: countRemMem :: forall e mr. (MemRead mr, Prim e) => mr -> (Count e, Count Word8)
- Data.Prim.Memory: createMemST :: (MemAlloc a, Prim e) => Count e -> (forall s. a s -> ST s b) -> (b, FrozenMem a)
+ Data.Prim.Memory: createMemST :: forall e b ma. (MemAlloc ma, Prim e) => Count e -> (forall s. ma s -> ST s b) -> (b, FrozenMem ma)
- Data.Prim.Memory: createMemST_ :: (MemAlloc a, Prim e) => Count e -> (forall s. a s -> ST s b) -> FrozenMem a
+ Data.Prim.Memory: createMemST_ :: (MemAlloc ma, Prim e) => Count e -> (forall s. ma s -> ST s b) -> FrozenMem ma
- Data.Prim.Memory: createZeroMemST :: (MemAlloc a, Prim e) => Count e -> (forall s. a s -> ST s b) -> (b, FrozenMem a)
+ Data.Prim.Memory: createZeroMemST :: forall e ma b. (MemAlloc ma, Prim e) => Count e -> (forall s. ma s -> ST s b) -> (b, FrozenMem ma)
- Data.Prim.Memory: createZeroMemST_ :: (MemAlloc a, Prim e) => Count e -> (forall s. a s -> ST s b) -> FrozenMem a
+ Data.Prim.Memory: createZeroMemST_ :: forall e ma b. (MemAlloc ma, Prim e) => Count e -> (forall s. ma s -> ST s b) -> FrozenMem ma
- Data.Prim.Memory: cycleMemN :: (MemAlloc a, MemRead r) => Int -> r -> FrozenMem a
+ Data.Prim.Memory: cycleMemN :: forall ma mr. (MemAlloc ma, MemRead mr) => Int -> mr -> FrozenMem ma
- Data.Prim.Memory: emptyMem :: MemAlloc a => FrozenMem a
+ Data.Prim.Memory: emptyMem :: forall ma. MemAlloc ma => FrozenMem ma
- Data.Prim.Memory: eqMem :: (MemRead r1, MemRead r2) => r1 -> r2 -> Bool
+ Data.Prim.Memory: eqMem :: (MemRead mr1, MemRead mr2) => mr1 -> mr2 -> Bool
- Data.Prim.Memory: foldrCountMem :: (MemRead r, Prim e) => Count e -> (e -> b -> b) -> b -> r -> b
+ Data.Prim.Memory: foldrCountMem :: forall e b mr. (MemRead mr, Prim e) => Count e -> (e -> b -> b) -> b -> mr -> b
- Data.Prim.Memory: freezeCloneMem :: (MemAlloc a, MonadPrim s m) => a s -> m (FrozenMem a)
+ Data.Prim.Memory: freezeCloneMem :: forall ma m s. (MemAlloc ma, MonadPrim s m) => ma s -> m (FrozenMem ma)
- Data.Prim.Memory: freezeCopyMem :: (MemAlloc a, MonadPrim s m, Prim e) => a s -> Off e -> Count e -> m (FrozenMem a)
+ Data.Prim.Memory: freezeCopyMem :: forall e ma m s. (Prim e, MemAlloc ma, MonadPrim s m) => ma s -> Off e -> Count e -> m (FrozenMem ma)
- Data.Prim.Memory: freezeMem :: (MemAlloc a, MonadPrim s m) => a s -> m (FrozenMem a)
+ Data.Prim.Memory: freezeMem :: (MemAlloc ma, MonadPrim s m) => ma s -> m (FrozenMem ma)
- Data.Prim.Memory: fromByteListMem :: MemAlloc a => [Word8] -> FrozenMem a
+ Data.Prim.Memory: fromByteListMem :: forall ma. MemAlloc ma => [Word8] -> FrozenMem ma
- Data.Prim.Memory: fromListMem :: (MemAlloc a, Prim e) => [e] -> FrozenMem a
+ Data.Prim.Memory: fromListMem :: forall e ma. (Prim e, MemAlloc ma) => [e] -> FrozenMem ma
- Data.Prim.Memory: fromListMemN :: (MemAlloc a, Prim e) => Count e -> [e] -> (Ordering, FrozenMem a)
+ Data.Prim.Memory: fromListMemN :: forall e ma. (Prim e, MemAlloc ma) => Count e -> [e] -> (Either [e] (Count e), FrozenMem ma)
- Data.Prim.Memory: getByteCountMem :: (MemAlloc a, MonadPrim s m) => a s -> m (Count Word8)
+ Data.Prim.Memory: getByteCountMem :: (MemAlloc ma, MonadPrim s m) => ma s -> m (Count Word8)
- Data.Prim.Memory: getCountMem :: (MemAlloc r, MonadPrim s m, Prim e) => r s -> m (Count e)
+ Data.Prim.Memory: getCountMem :: forall e ma m s. (MemAlloc ma, MonadPrim s m, Prim e) => ma s -> m (Count e)
- Data.Prim.Memory: getCountRemMem :: (MemAlloc r, MonadPrim s m, Prim e) => r s -> m (Count e, Count Word8)
+ Data.Prim.Memory: getCountRemMem :: forall e ma m s. (MemAlloc ma, MonadPrim s m, Prim e) => ma s -> m (Count e, Count Word8)
- Data.Prim.Memory: indexByteOffMem :: (MemRead r, Prim e) => r -> Off Word8 -> e
+ Data.Prim.Memory: indexByteOffMem :: (MemRead mr, Prim e) => mr -> Off Word8 -> e
- Data.Prim.Memory: indexOffMem :: (MemRead r, Prim e) => r -> Off e -> e
+ Data.Prim.Memory: indexOffMem :: (MemRead mr, Prim e) => mr -> Off e -> e
- Data.Prim.Memory: loadListMem :: (MonadPrim s m, MemAlloc r, Prim e) => [e] -> r s -> m Ordering
+ Data.Prim.Memory: loadListMem :: forall e ma m s. (Prim e, MemAlloc ma, MonadPrim s m) => [e] -> ma s -> m ([e], Count e)
- Data.Prim.Memory: loadListMemN :: (MemWrite r, MonadPrim s m, Prim e) => Count e -> Count Word8 -> [e] -> r s -> m Ordering
+ Data.Prim.Memory: loadListMemN :: forall e mw m s. (MemWrite mw, MonadPrim s m, Prim e) => Count e -> [e] -> mw s -> m ([e], Count e)
- Data.Prim.Memory: loadListMemN_ :: (MemWrite r, MonadPrim s m, Prim e) => Count e -> [e] -> r s -> m ()
+ Data.Prim.Memory: loadListMemN_ :: forall e mw m s. (Prim e, MemWrite mw, MonadPrim s m) => Count e -> [e] -> mw s -> m ()
- Data.Prim.Memory: loadListMem_ :: (MonadPrim s m, MemAlloc r, Prim e) => [e] -> r s -> m ()
+ Data.Prim.Memory: loadListMem_ :: forall e ma m s. (Prim e, MemAlloc ma, MonadPrim s m) => [e] -> ma s -> m ()
- Data.Prim.Memory: modifyFetchNewMem :: (MemWrite w, MonadPrim s m, Prim b) => w s -> Off b -> (b -> b) -> m b
+ Data.Prim.Memory: modifyFetchNewMem :: (MemWrite mw, MonadPrim s m, Prim e) => mw s -> Off e -> (e -> e) -> m e
- Data.Prim.Memory: modifyFetchNewMemM :: (MemWrite w, MonadPrim s m, Prim b) => w s -> Off b -> (b -> m b) -> m b
+ Data.Prim.Memory: modifyFetchNewMemM :: (MemWrite mw, MonadPrim s m, Prim e) => mw s -> Off e -> (e -> m e) -> m e
- Data.Prim.Memory: modifyFetchOldMem :: (MemWrite w, MonadPrim s m, Prim b) => w s -> Off b -> (b -> b) -> m b
+ Data.Prim.Memory: modifyFetchOldMem :: (MemWrite mw, MonadPrim s m, Prim e) => mw s -> Off e -> (e -> e) -> m e
- Data.Prim.Memory: modifyFetchOldMemM :: (MemWrite w, MonadPrim s m, Prim b) => w s -> Off b -> (b -> m b) -> m b
+ Data.Prim.Memory: modifyFetchOldMemM :: (MemWrite mw, MonadPrim s m, Prim e) => mw s -> Off e -> (e -> m e) -> m e
- Data.Prim.Memory: moveByteOffMem :: (MemWrite w, MonadPrim s m, MemWrite w', Prim e) => w' s -> Off Word8 -> w s -> Off Word8 -> Count e -> m ()
+ Data.Prim.Memory: moveByteOffMem :: (MemWrite mw, MonadPrim s m, MemWrite mw', Prim e) => mw' s -> Off Word8 -> mw s -> Off Word8 -> Count e -> m ()
- Data.Prim.Memory: moveMem :: (MonadPrim s m, MemWrite w1, MemWrite w2, Prim e) => w1 s -> Off e -> w2 s -> Off e -> Count e -> m ()
+ Data.Prim.Memory: moveMem :: (MonadPrim s m, MemWrite mw1, MemWrite mw2, Prim e) => mw1 s -> Off e -> mw2 s -> Off e -> Count e -> m ()
- Data.Prim.Memory: readByteOffMem :: (MemWrite w, MonadPrim s m, Prim e) => w s -> Off Word8 -> m e
+ Data.Prim.Memory: readByteOffMem :: (MemWrite mw, MonadPrim s m, Prim e) => mw s -> Off Word8 -> m e
- Data.Prim.Memory: readOffMem :: (MemWrite w, MonadPrim s m, Prim e) => w s -> Off e -> m e
+ Data.Prim.Memory: readOffMem :: (MemWrite mw, MonadPrim s m, Prim e) => mw s -> Off e -> m e
- Data.Prim.Memory: setMem :: (MemWrite w, MonadPrim s m, Prim e) => w s -> Off e -> Count e -> e -> m ()
+ Data.Prim.Memory: setMem :: (MemWrite mw, MonadPrim s m, Prim e) => mw s -> Off e -> Count e -> e -> m ()
- Data.Prim.Memory: singletonMem :: forall e a. (MemAlloc a, Prim e) => e -> FrozenMem a
+ Data.Prim.Memory: singletonMem :: forall e ma. (MemAlloc ma, Prim e) => e -> FrozenMem ma
- Data.Prim.Memory: thawCloneMem :: (MemRead r, MemAlloc a, MonadPrim s m) => r -> m (a s)
+ Data.Prim.Memory: thawCloneMem :: forall mr ma m s. (MemRead mr, MemAlloc ma, MonadPrim s m) => mr -> m (ma s)
- Data.Prim.Memory: thawCopyMem :: (MemRead r, MemAlloc a, MonadPrim s m, Prim e) => r -> Off e -> Count e -> m (a s)
+ Data.Prim.Memory: thawCopyMem :: forall e mr ma m s. (Prim e, MemRead mr, MemAlloc ma, MonadPrim s m) => mr -> Off e -> Count e -> m (ma s)
- Data.Prim.Memory: thawMem :: (MemAlloc a, MonadPrim s m) => FrozenMem a -> m (a s)
+ Data.Prim.Memory: thawMem :: (MemAlloc ma, MonadPrim s m) => FrozenMem ma -> m (ma s)
- Data.Prim.Memory: toByteListMem :: MemAlloc a => FrozenMem a -> [Word8]
+ Data.Prim.Memory: toByteListMem :: forall ma. MemAlloc ma => FrozenMem ma -> [Word8]
- Data.Prim.Memory: toListMem :: (MemRead r, Prim e) => r -> [e]
+ Data.Prim.Memory: toListMem :: forall e mr. (MemRead mr, Prim e) => mr -> [e]
- Data.Prim.Memory: toListSlackMem :: forall e r. (MemRead r, Prim e) => r -> ([e], [Word8])
+ Data.Prim.Memory: toListSlackMem :: forall e mr. (MemRead mr, Prim e) => mr -> ([e], [Word8])
- Data.Prim.Memory: type family FrozenMem a = (fa :: Type) | fa -> a;
+ Data.Prim.Memory: type family FrozenMem ma = (fm :: Type) | fm -> ma;
- Data.Prim.Memory: writeByteOffMem :: (MemWrite w, MonadPrim s m, Prim e) => w s -> Off Word8 -> e -> m ()
+ Data.Prim.Memory: writeByteOffMem :: (MemWrite mw, MonadPrim s m, Prim e) => mw s -> Off Word8 -> e -> m ()
- Data.Prim.Memory: writeOffMem :: (MemWrite w, MonadPrim s m, Prim e) => w s -> Off e -> e -> m ()
+ Data.Prim.Memory: writeOffMem :: (MemWrite mw, MonadPrim s m, Prim e) => mw s -> Off e -> e -> m ()
- Data.Prim.Memory.Bytes: fromListBytesN :: (Prim e, Typeable p) => Count e -> [e] -> (Ordering, Bytes p)
+ Data.Prim.Memory.Bytes: fromListBytesN :: (Prim e, Typeable p) => Count e -> [e] -> (Either [e] (Count e), Bytes p)
- Data.Prim.Memory.Bytes: loadListMBytes :: (MonadPrim s m, Prim e) => [e] -> MBytes p s -> m Ordering
+ Data.Prim.Memory.Bytes: loadListMBytes :: (Prim e, Typeable p, MonadPrim s m) => [e] -> MBytes p s -> m ([e], Count e)
- Data.Prim.Memory.Bytes: loadListMBytes_ :: (MonadPrim s m, Prim e) => [e] -> MBytes p s -> m ()
+ Data.Prim.Memory.Bytes: loadListMBytes_ :: (Prim e, Typeable p, MonadPrim s m) => [e] -> MBytes p s -> m ()
- Data.Prim.Memory.Bytes: relaxPinnedBytes :: Bytes p -> Bytes 'Inc
+ Data.Prim.Memory.Bytes: relaxPinnedBytes :: Bytes 'Pin -> Bytes p
- Data.Prim.Memory.Bytes: relaxPinnedMBytes :: MBytes p e -> MBytes 'Inc e
+ Data.Prim.Memory.Bytes: relaxPinnedMBytes :: MBytes 'Pin e -> MBytes p e
Files
- CHANGELOG.md +7/−1
- bench/Bench.hs +3/−3
- bench/Conversion.hs +3/−4
- primal-memory.cabal +25/−19
- src/Data/Prim/Memory.hs +87/−70
- src/Data/Prim/Memory/Addr.hs +49/−35
- src/Data/Prim/Memory/ByteArray.hs +0/−311
- src/Data/Prim/Memory/ByteString.hs +58/−18
- src/Data/Prim/Memory/Bytes.hs +23/−48
- src/Data/Prim/Memory/Bytes/Internal.hs +93/−37
- src/Data/Prim/Memory/ForeignPtr.hs +22/−36
- src/Data/Prim/Memory/Internal.hs +2353/−976
- src/Data/Prim/Memory/PrimArray.hs +310/−0
- src/Data/Prim/Memory/Ptr.hs +7/−7
- src/Data/Prim/Memory/Text.hs +54/−0
- tests/doctests.hs +6/−0
CHANGELOG.md view
@@ -1,5 +1,11 @@ # Changelog for primal-memory -## 0.1.0.0+## 0.2.0++* Rename `ByteArray` -> `PrimArray`+* Improve `fromList` conversion+* Get rid of `allocByteCountMem` in favor of more general `allocMem`++## 0.1.0 * Initial release
bench/Bench.hs view
@@ -24,11 +24,11 @@ mb1 <- allocAlignedMBytes n64 mb2 <- allocAlignedMBytes n64 b1 <- freezeMBytes mb1- mba <- BA.newAlignedPinnedByteArray (fromCount (n :: Count Word64)) 8+ mba <- BA.newAlignedPinnedByteArray (unCountBytes (n :: Count Word64)) 8 ba <- BA.unsafeFreezeByteArray mba -- Ensure that arrays are equal by filling them with zeros- mbaEq1 <- BA.newAlignedPinnedByteArray (fromCount (n :: Count Word64)) 8- mbaEq2 <- BA.newAlignedPinnedByteArray (fromCount (n :: Count Word64)) 8+ mbaEq1 <- BA.newAlignedPinnedByteArray (unCountBytes (n :: Count Word64)) 8+ mbaEq2 <- BA.newAlignedPinnedByteArray (unCountBytes (n :: Count Word64)) 8 BA.setByteArray mbaEq1 0 (unCount n64) (0 :: Word64) BA.setByteArray mbaEq2 0 (unCount n64) (0 :: Word64) defaultMain
bench/Conversion.hs view
@@ -13,7 +13,6 @@ import qualified Foreign.ForeignPtr as GHC import Foreign.Storable import Data.Prim.Memory.ForeignPtr-import Data.Semigroup import qualified Data.Primitive.ByteArray as BA main :: IO ()@@ -26,13 +25,13 @@ mb2 <- allocAlignedMBytes n64 mb3 <- allocAlignedMBytes n64 let fp = toForeignPtrMBytes mb3- mba <- BA.newAlignedPinnedByteArray (fromCount (n :: Count Word64)) 8+ mba <- BA.newAlignedPinnedByteArray (unCountBytes (n :: Count Word64)) 8 ba <- BA.unsafeFreezeByteArray mba -- Ensure that arrays are equal by filling them with zeros bEq1 <- freezeMBytes =<< callocAlignedMBytes n64 bEq2 <- freezeMBytes =<< callocAlignedMBytes n64- mbaEq1 <- BA.newAlignedPinnedByteArray (fromCount (n :: Count Word64)) 8- mbaEq2 <- BA.newAlignedPinnedByteArray (fromCount (n :: Count Word64)) 8+ mbaEq1 <- BA.newAlignedPinnedByteArray (unCountBytes (n :: Count Word64)) 8+ mbaEq2 <- BA.newAlignedPinnedByteArray (unCountBytes (n :: Count Word64)) 8 BA.setByteArray mbaEq1 0 (unCount n64) (0 :: Word64) BA.setByteArray mbaEq2 0 (unCount n64) (0 :: Word64) baEq1 <- BA.unsafeFreezeByteArray mbaEq1
primal-memory.cabal view
@@ -1,5 +1,5 @@ name: primal-memory-version: 0.1.0.0+version: 0.2.0.0 synopsis: Unified interface for memory managemenet. description: Please see the README on GitHub at <https://github.com/lehins/primal#readme> homepage: https://github.com/lehins/primal@@ -25,33 +25,39 @@ library hs-source-dirs: src exposed-modules: Data.Prim.Memory- , Data.Prim.Memory.ByteArray- , Data.Prim.Memory.Bytes , Data.Prim.Memory.Addr , Data.Prim.Memory.ByteString+ , Data.Prim.Memory.Bytes+ , Data.Prim.Memory.ForeignPtr+ , Data.Prim.Memory.PrimArray , Data.Prim.Memory.Ptr+ , Data.Prim.Memory.Text , Data.Prim.Memory.Internal- , Data.Prim.Memory.ForeignPtr other-modules: Data.Prim.Memory.Bytes.Internal- build-depends: base >= 4.8 && < 5- , bytestring+ build-depends: base >= 4.9 && < 5+ , bytestring >= 0.10.4 , deepseq- , primal+ , primal >= 0.2+ , text >= 1.1.1.3 default-language: Haskell2010 ghc-options: -Wall--- test-suite doctests--- type: exitcode-stdio-1.0--- hs-source-dirs: tests--- main-is: doctests.hs--- build-depends: base--- , doctest >=0.15--- , prim-bytes--- , template-haskell--- default-language: Haskell2010--- ghc-options: -Wall--- -fno-warn-orphans--- -threaded++test-suite doctests+ type: exitcode-stdio-1.0+ hs-source-dirs: tests+ main-is: doctests.hs+ build-depends: base+ , bytestring+ , doctest >=0.15+ , primal+ , primal-memory+ , QuickCheck+ , template-haskell+ default-language: Haskell2010+ ghc-options: -Wall+ -threaded+ benchmark bench type: exitcode-stdio-1.0
src/Data/Prim/Memory.hs view
@@ -7,83 +7,100 @@ -- Portability : non-portable -- module Data.Prim.Memory- ( Pinned(..)+ ( module Data.Prim+ , Pinned(..) -- * Immutable , Bytes , MemRead- , countMem- , countRemMem- , indexOffMem- , eqMem- , compareMem+ -- ** Size+ , countMem -- DOC: [x], DOCTEST [x], TEST: [ ]+ , countRemMem -- DOC: [x], DOCTEST [x], TEST: [ ]+ , byteCountMem -- DOC: [x], DOCTEST [ ], TEST: [x]+ -- ** Index+ , indexOffMem -- DOC: [x], DOCTEST [ ], TEST: [x]+ , indexByteOffMem -- DOC: [x], DOCTEST [ ], TEST: [x]+ -- ** Construct+ , emptyMem -- DOC: [x], DOCTEST [x], TEST: [x]+ , singletonMem -- DOC: [x], DOCTEST [x], TEST: [ ]+ , cycleMemN -- DOC: [x], DOCTEST [x], TEST: [ ]+ , createMemST -- DOC: [ ], DOCTEST [ ], TEST: [ ]+ , createMemST_ -- DOC: [ ], DOCTEST [ ], TEST: [ ]+ , createZeroMemST -- DOC: [ ], DOCTEST [ ], TEST: [ ]+ , createZeroMemST_ -- DOC: [x], DOCTEST [x], TEST: [ ]+ -- ** Copy+ , cloneMem -- DOC: [x], DOCTEST [x], TEST: [ ]+ , copyMem -- DOC: [x], DOCTEST [ ], TEST: [x]+ , copyByteOffMem -- DOC: [x], DOCTEST [ ], TEST: [ ]+ , copyByteOffToMBytesMem -- DOC: [x], DOCTEST [ ], TEST: [x]+ , copyByteOffToPtrMem -- DOC: [x], DOCTEST [ ], TEST: [x]+ -- ** Compare+ , eqMem -- DOC: [ ], DOCTEST [ ], TEST: [ ]+ , compareMem -- DOC: [ ], DOCTEST [ ], TEST: [ ]+ , compareByteOffMem -- DOC: [x], DOCTEST [ ], TEST: [ ]+ , compareByteOffToPtrMem -- DOC: [x], DOCTEST [ ], TEST: [x]+ , compareByteOffToBytesMem -- DOC: [x], DOCTEST [ ], TEST: [x]+ -- ** Convert+ , convertMem -- DOC: [ ], DOCTEST [ ], TEST: [ ]+ -- *** To list+ , toListMem -- DOC: [x], DOCTEST [x], TEST: [x]+ , toListSlackMem -- DOC: [x], DOCTEST [x], TEST: [x]+ , toByteListMem -- DOC: [x], DOCTEST [x], TEST: [x]+ , foldrCountMem -- DOC: [x], DOCTEST [-], TEST: [-]+ , showsHexMem -- DOC: [x], DOCTEST [x], TEST: [ ]++ -- *** From list+ , fromListMem -- DOC: [x], DOCTEST [x], TEST: [x]+ , fromByteListMem -- DOC: [x], DOCTEST [x], TEST: [x]+ , fromListMemN -- DOC: [x], DOCTEST [x], TEST: [x]+ , fromListZeroMemN -- DOC: [x], DOCTEST [x], TEST: [ ]+ , fromListZeroMemN_ -- DOC: [x], DOCTEST [x], TEST: [ ] -- * Mutable , MBytes- , MemAlloc(FrozenMem) , MemWrite- , getCountMem- , getCountRemMem- , readOffMem- , writeOffMem- , modifyFetchOldMem- , modifyFetchOldMemM- , modifyFetchNewMem- , modifyFetchNewMemM- , setMem- , copyMem- , moveMem-+ , MemAlloc(FrozenMem) , MemState(..)- , allocMem- , allocZeroMem- , thawMem- , thawCloneMem- , thawCopyMem- , freezeMem- , freezeCloneMem- , freezeCopyMem- , createMemST- , createMemST_- , createZeroMemST- , createZeroMemST_- , emptyMem- , singletonMem- , cycleMemN- -- * Byte operations- -- $byteOperations- -- ** Immutable- , byteCountMem- , indexByteOffMem- , compareByteOffMem- -- ** Mutable- , allocByteCountMem- , getByteCountMem- , readByteOffMem- , writeByteOffMem- , copyByteOffMem- , moveByteOffMem- -- * Conversion- , convertMem- -- ** List- , toListMem- , toListSlackMem- , toByteListMem- , fromByteListMem-- , fromListMem- , fromListMemN- , loadListMem- , loadListMem_- , loadListMemN- , loadListMemN_- -- *** Helpers- , foldrCountMem+ -- ** Size+ , getCountMem -- DOC: [ ], DOCTEST [ ], TEST: [ ]+ , getCountRemMem -- DOC: [ ], DOCTEST [ ], TEST: [ ]+ , getByteCountMem -- DOC: [ ], DOCTEST [ ], TEST: [ ]+ -- ** Read+ , readOffMem -- DOC: [ ], DOCTEST [ ], TEST: [ ]+ , readByteOffMem -- DOC: [ ], DOCTEST [ ], TEST: [ ]+ -- ** Write+ , writeOffMem -- DOC: [x], DOCTEST [ ], TEST: [x]+ , writeByteOffMem -- DOC: [x], DOCTEST [ ], TEST: [x]+ , setMem -- DOC: [x], DOCTEST [ ], TEST: [x]+ , modifyFetchOldMem -- DOC: [ ], DOCTEST [ ], TEST: [ ]+ , modifyFetchOldMemM -- DOC: [ ], DOCTEST [ ], TEST: [ ]+ , modifyFetchNewMem -- DOC: [ ], DOCTEST [ ], TEST: [ ]+ , modifyFetchNewMemM -- DOC: [ ], DOCTEST [ ], TEST: [ ]+ -- ** Allocate+ , allocMem -- DOC: [x], DOCTEST [ ], TEST: [ ]+ , allocZeroMem -- DOC: [x], DOCTEST [x], TEST: [ ]+ , thawMem -- DOC: [x], DOCTEST [ ], TEST: [ ]+ , thawCloneMem -- DOC: [ ], DOCTEST [ ], TEST: [ ]+ , thawCopyMem -- DOC: [ ], DOCTEST [ ], TEST: [ ]+ , freezeMem -- DOC: [x], DOCTEST [ ], TEST: [ ]+ , freezeCloneMem -- DOC: [ ], DOCTEST [ ], TEST: [ ]+ , freezeCopyMem -- DOC: [ ], DOCTEST [ ], TEST: [ ]+ , resizeMem -- DOC: [x], DOCTEST [ ], TEST: [ ]+ , withScrubbedMem -- DOC: [ ], DOCTEST [ ], TEST: [ ]+ -- ** Move+ , moveMem -- DOC: [ ], DOCTEST [ ], TEST: [x]+ , moveByteOffMem -- DOC: [x], DOCTEST [ ], TEST: [ ]+ , moveByteOffToMBytesMem -- DOC: [x], DOCTEST [ ], TEST: [x]+ , moveByteOffToPtrMem -- DOC: [x], DOCTEST [ ], TEST: [x]+ -- ** Load list+ , loadListMem -- DOC: [x], DOCTEST [x], TEST: [x]+ , loadListMem_ -- DOC: [x], DOCTEST [x], TEST: [ ]+ , loadListMemN -- DOC: [x], DOCTEST [ ], TEST: [ ]+ , loadListMemN_ -- DOC: [x], DOCTEST [ ], TEST: [ ]+ -- *** With offset+ , loadListOffMem -- DOC: [ ], DOCTEST [ ], TEST: [ ]+ , loadListOffMemN -- DOC: [ ], DOCTEST [ ], TEST: [ ]+ , loadListByteOffMem -- DOC: [x], DOCTEST [x], TEST: [ ]+ , loadListByteOffMemN -- DOC: [x], DOCTEST [x], TEST: [ ] ) where +import Data.Prim import Data.Prim.Memory.Internal----- $byteOperations------ More often than not it is desired to operate on the offset and count of the actual type--- of intereset we are dealing with in memory. But sometimes it is necessary to specify--- things in 8bit steps, this is where byte size offsets and counts will come in handy.
src/Data/Prim/Memory/Addr.hs view
@@ -134,26 +134,29 @@ import Data.Prim.Atomic import Data.Prim.Class import Data.Prim.Memory.Bytes+import Data.Prim.Memory.Bytes.Internal import Data.Prim.Memory.ByteString import Data.Prim.Memory.ForeignPtr import Data.Prim.Memory.Internal import Data.Prim.Memory.Ptr import qualified Data.Semigroup as Semigroup import Foreign.Prim+import Unsafe.Coerce +-- | Immutable read-only address data Addr e = Addr { addrAddr# :: Addr# , addrBytes :: {-# UNPACK #-}!(Bytes 'Pin) }-type role Addr representational-+type role Addr nominal +-- | Mutable address data MAddr e s = MAddr { mAddrAddr# :: Addr# , mAddrMBytes :: {-# UNPACK #-}!(MBytes 'Pin s) }-type role MAddr representational nominal+type role MAddr nominal nominal @@ -169,7 +172,7 @@ instance Prim e => IsList (Addr e) where type Item (Addr e) = e fromList = fromListMem- fromListN n = fromListMemN_ (Count n)+ fromListN n = fromListZeroMemN_ (Count n) toList = toListMem instance Semigroup.Semigroup (Addr e) where@@ -189,6 +192,9 @@ castMAddr :: MAddr e s -> MAddr b s castMAddr (MAddr a mb) = MAddr a mb +castStateMAddr :: MAddr e s' -> MAddr b s+castStateMAddr = unsafeCoerce+ isSameAddr :: Addr e -> Addr e -> Bool isSameAddr (Addr a1# _) (Addr a2# _) = isTrue# (a1# `eqAddr#` a2#) @@ -245,13 +251,13 @@ plusOffAddr :: Prim e => Addr e -> Off e -> Addr e-plusOffAddr (Addr addr# b) off = Addr (addr# `plusAddr#` fromOff# off) b+plusOffAddr (Addr addr# b) off = Addr (addr# `plusAddr#` unOffBytes# off) b plusOffMAddr :: Prim e => MAddr e s -> Off e -> MAddr e s-plusOffMAddr (MAddr addr# mb) off = MAddr (addr# `plusAddr#` fromOff# off) mb+plusOffMAddr (MAddr addr# mb) off = MAddr (addr# `plusAddr#` unOffBytes# off) mb curOffAddr :: Prim e => Addr e -> Off e-curOffAddr a@(Addr addr# b) = offAsProxy a (Ptr addr# `minusOffPtr` toPtrBytes b)+curOffAddr a@(Addr addr# b) = (Ptr addr# `minusOffPtr` toPtrBytes b) `offForProxyTypeOf` a curByteOffAddr :: Addr e -> Off Word8 curByteOffAddr (Addr addr# b) = Ptr addr# `minusByteOffPtr` toPtrBytes b@@ -314,32 +320,40 @@ toForeignPtrMAddr :: MAddr e s -> ForeignPtr e toForeignPtrMAddr (MAddr addr# (MBytes mba#)) = ForeignPtr addr# (PlainPtr (unsafeCoerce# mba#)) --- | Discarding the original `ForeignPtr` will trigger finalizers that were attached to--- it, because `Addr` does not retain any finalizers. This is a unsafe cast therefore--- modification of `ForeignPtr` will be reflected in resulting immutable `Addr`. Pointer--- created with @malloc@ cannot be converted to `Addr` and will result in `Nothing`+-- | This is a unsafe cast therefore modification of `ForeignPtr` will be reflected in+-- resulting immutable `Addr`. Pointer created with @malloc@ cannot be converted to `Addr`+-- and will result in `Nothing` -- -- @since 0.1.0 fromForeignPtrAddr :: ForeignPtr e -> Maybe (Addr e)-fromForeignPtrAddr (ForeignPtr addr# c) =- case c of- PlainPtr mba# -> Just (Addr addr# (unsafePerformIO (freezeMBytes (MBytes mba#))))- MallocPtr mba# _ -> Just (Addr addr# (unsafePerformIO (freezeMBytes (MBytes mba#))))- _ -> Nothing+fromForeignPtrAddr fptr =+ unsafePerformIO $ fromForeignPtrIO fptr >>= traverse freezeMAddr + -- | Discarding the original ForeignPtr will trigger finalizers that were attached to it, -- because `MAddr` does not retain any finalizers. Pointer created with @malloc@ cannot be -- converted to `MAddr` and will result in `Nothing` -- -- @since 0.1.0 fromForeignPtrMAddr :: ForeignPtr e -> Maybe (MAddr e s)-fromForeignPtrMAddr (ForeignPtr addr# c) =- case c of- PlainPtr mba# -> Just (MAddr addr# (MBytes (unsafeCoerce# mba#)))- MallocPtr mba# _ -> Just (MAddr addr# (MBytes (unsafeCoerce# mba#)))- _ -> Nothing+fromForeignPtrMAddr fptr =+ unsafePerformIO (fmap castStateMAddr <$> fromForeignPtrIO fptr)+ -- case c of+ -- PlainPtr mba# -> Just (MAddr addr# (MBytes (unsafeCoerce# mba#)))+ -- MallocPtr mba# _ -> Just (MAddr addr# (MBytes (unsafeCoerce# mba#)))+ -- _ -> Nothing +fromForeignPtrIO :: ForeignPtr e -> IO (Maybe (MAddr e RW))+fromForeignPtrIO fptr =+ onForeignPtrContents fptr checkConvert $ \_ -> pure Nothing+ where+ checkConvert addr# mba# checkFinalizers = do+ hasFinalizers <- checkFinalizers+ pure $+ if hasFinalizers+ then Nothing+ else Just (MAddr addr# (MBytes mba#)) withAddrMAddr# :: MonadPrim s m => MAddr e s -> (Addr# -> m b) -> m b withAddrMAddr# (MAddr addr# mb) f = do@@ -374,11 +388,10 @@ instance MemAlloc (MAddr e) where type FrozenMem (MAddr e) = Addr e- getByteCountMem = getByteCountMAddr {-# INLINE getByteCountMem #-}- allocByteCountMem = fmap castMAddr . allocMAddr- {-# INLINE allocByteCountMem #-}+ allocMem = fmap castMAddr . allocMAddr+ {-# INLINE allocMem #-} thawMem = thawAddr {-# INLINE thawMem #-} freezeMem = freezeMAddr@@ -404,7 +417,8 @@ withPtrAccess addr $ \ptr1 -> pure $ compareByteOffPtrToPtr ptr1 off1 ptr2 off2 c {-# INLINE compareByteOffToPtrMem #-} compareByteOffToBytesMem addr off1 bytes off2 c =- withPtrAccess addr $ \ptr1 -> pure $ compareByteOffPtrToBytes ptr1 off1 bytes off2 c+ unsafeInlineIO $ withPtrAccess addr $ \ptr1 ->+ pure $! compareByteOffPtrToBytes ptr1 off1 bytes off2 c {-# INLINE compareByteOffToBytesMem #-} compareByteOffMem mem1 off1 addr off2 c = unsafeInlineIO $ withPtrAccess addr $ \ptr2 -> compareByteOffToPtrMem mem1 off1 ptr2 off2 c@@ -533,7 +547,7 @@ toShortByteStringAddr :: Addr Word8 -> (ShortByteString, Off Word8) toShortByteStringAddr = first toShortByteStringBytes . toBytesAddr --- | /O(1)/ - Cast an immutable `ShortByteString` to an immutable `Addr`. In a most common+-- | /O(n)/ - Convert an immutable `ShortByteString` to an immutable `Addr`. In a most common -- case when `ShortByteString` is not backed by pinned memory, this function will return -- `Nothing`. --@@ -549,7 +563,7 @@ fromByteStringAddr (PS fptr i n) = case fromForeignPtrAddr fptr of Just addr -> (addr `plusOffAddr` Off i, Count n)- Nothing -> byteStringConvertError "It was allocated outside of 'bytestring' package"+ Nothing -> byteStringConvertError "ByteString was allocated outside of 'bytestring' package" -- | /O(1)/ - Cast an immutable `ByteString` to a mutable `MAddr`. Also returns the -- original length of ByteString, which will be less or equal to `getCountOfMAddr` in the@@ -1026,33 +1040,33 @@ prefetchOffAddr0 :: (MonadPrim s m, Prim e) => Addr e -> Off e -> m ()-prefetchOffAddr0 (Addr addr# _) off = prim_ (prefetchAddr0# addr# (fromOff# off))+prefetchOffAddr0 (Addr addr# _) off = prim_ (prefetchAddr0# addr# (unOffBytes# off)) {-# INLINE prefetchOffAddr0 #-} prefetchOffMAddr0 :: (MonadPrim s m, Prim e) => MAddr e s -> Off e -> m ()-prefetchOffMAddr0 (MAddr maddr# _) off = prim_ (prefetchAddr0# maddr# (fromOff# off))+prefetchOffMAddr0 (MAddr maddr# _) off = prim_ (prefetchAddr0# maddr# (unOffBytes# off)) {-# INLINE prefetchOffMAddr0 #-} prefetchOffAddr1 :: (MonadPrim s m, Prim e) => Addr e -> Off e -> m ()-prefetchOffAddr1 (Addr addr# _) off = prim_ (prefetchAddr1# addr# (fromOff# off))+prefetchOffAddr1 (Addr addr# _) off = prim_ (prefetchAddr1# addr# (unOffBytes# off)) {-# INLINE prefetchOffAddr1 #-} prefetchOffMAddr1 :: (MonadPrim s m, Prim e) => MAddr e s -> Off e -> m ()-prefetchOffMAddr1 (MAddr maddr# _) off = prim_ (prefetchAddr1# maddr# (fromOff# off))+prefetchOffMAddr1 (MAddr maddr# _) off = prim_ (prefetchAddr1# maddr# (unOffBytes# off)) {-# INLINE prefetchOffMAddr1 #-} prefetchOffAddr2 :: (MonadPrim s m, Prim e) => Addr e -> Off e -> m ()-prefetchOffAddr2 (Addr addr# _) off = prim_ (prefetchAddr2# addr# (fromOff# off))+prefetchOffAddr2 (Addr addr# _) off = prim_ (prefetchAddr2# addr# (unOffBytes# off)) {-# INLINE prefetchOffAddr2 #-} prefetchOffMAddr2 :: (MonadPrim s m, Prim e) => MAddr e s -> Off e -> m ()-prefetchOffMAddr2 (MAddr maddr# _) off = prim_ (prefetchAddr2# maddr# (fromOff# off))+prefetchOffMAddr2 (MAddr maddr# _) off = prim_ (prefetchAddr2# maddr# (unOffBytes# off)) {-# INLINE prefetchOffMAddr2 #-} prefetchOffAddr3 :: (MonadPrim s m, Prim e) => Addr e -> Off e -> m ()-prefetchOffAddr3 (Addr addr# _) off = prim_ (prefetchAddr3# addr# (fromOff# off))+prefetchOffAddr3 (Addr addr# _) off = prim_ (prefetchAddr3# addr# (unOffBytes# off)) {-# INLINE prefetchOffAddr3 #-} prefetchOffMAddr3 :: (MonadPrim s m, Prim e) => MAddr e s -> Off e -> m ()-prefetchOffMAddr3 (MAddr maddr# _) off = prim_ (prefetchAddr3# maddr# (fromOff# off))+prefetchOffMAddr3 (MAddr maddr# _) off = prim_ (prefetchAddr3# maddr# (unOffBytes# off)) {-# INLINE prefetchOffMAddr3 #-}
− src/Data/Prim/Memory/ByteArray.hs
@@ -1,311 +0,0 @@-{-# LANGUAGE DataKinds #-}-{-# LANGUAGE FlexibleContexts #-}-{-# LANGUAGE FlexibleInstances #-}-{-# LANGUAGE GeneralizedNewtypeDeriving #-}-{-# LANGUAGE KindSignatures #-}-{-# LANGUAGE MultiParamTypeClasses #-}-{-# LANGUAGE RankNTypes #-}-{-# LANGUAGE RoleAnnotations #-}-{-# LANGUAGE ScopedTypeVariables #-}-{-# LANGUAGE TypeFamilies #-}--- |--- Module : Data.Prim.Memory.ByteArray--- Copyright : (c) Alexey Kuleshevich 2020--- License : BSD3--- Maintainer : Alexey Kuleshevich <alexey@kuleshevi.ch>--- Stability : experimental--- Portability : non-portable----module Data.Prim.Memory.ByteArray- ( ByteArray(..)- , MByteArray(..)- , Pinned(..)- , fromBytesByteArray- , toBytesByteArray- , castByteArray- , fromMBytesMByteArray- , toMBytesMByteArray- , castMByteArray- , allocMByteArray- , allocPinnedMByteArray- , allocAlignedMByteArray- , allocUnpinnedMByteArray- , shrinkMByteArray- , resizeMByteArray- , reallocMByteArray- , isPinnedByteArray- , isPinnedMByteArray-- , thawByteArray- , freezeMByteArray- , sizeByteArray- , getSizeMByteArray- , readMByteArray- , writeMByteArray-- , setMByteArray- , copyByteArrayToMByteArray- , moveMByteArrayToMByteArray- ) where--import Control.DeepSeq-import Control.Prim.Monad-import Foreign.Prim-import Data.Prim-import Data.Prim.Memory.Bytes-import Data.Prim.Memory.Internal-import Data.Prim.Memory.ForeignPtr----- | An immutable array of bytes of type @e@-newtype ByteArray (p :: Pinned) e = ByteArray (Bytes p)- deriving (NFData, Semigroup, Monoid, MemRead)-type role ByteArray nominal nominal---- | A mutable array of bytes of type @e@-newtype MByteArray (p :: Pinned) e s = MByteArray (MBytes p s)- deriving (NFData, MemWrite)-type role MByteArray nominal nominal nominal---- | Read-only access, but it is not enforced.-instance PtrAccess s (ByteArray 'Pin e) where- toForeignPtr = pure . toForeignPtrBytes . toBytesByteArray- {-# INLINE toForeignPtr #-}- withPtrAccess b = withPtrBytes (toBytesByteArray b)- {-# INLINE withPtrAccess #-}- withNoHaltPtrAccess b = withNoHaltPtrBytes (toBytesByteArray b)- {-# INLINE withNoHaltPtrAccess #-}--instance PtrAccess s (MByteArray 'Pin e s) where- toForeignPtr = pure . toForeignPtrMBytes . toMBytesMByteArray- {-# INLINE toForeignPtr #-}- withPtrAccess mb = withPtrMBytes (toMBytesMByteArray mb)- {-# INLINE withPtrAccess #-}- withNoHaltPtrAccess mb = withNoHaltPtrMBytes (toMBytesMByteArray mb)- {-# INLINE withNoHaltPtrAccess #-}--instance Typeable p => MemAlloc (MByteArray p e) where- type FrozenMem (MByteArray p e) = ByteArray p e- getByteCountMem = getByteCountMem . toMBytesMByteArray- {-# INLINE getByteCountMem #-}- allocByteCountMem = fmap fromMBytesMByteArray . allocMBytes- {-# INLINE allocByteCountMem #-}- thawMem = thawByteArray- {-# INLINE thawMem #-}- freezeMem = freezeMByteArray- {-# INLINE freezeMem #-}- resizeMem mba = fmap fromMBytesMByteArray . reallocMBytes (toMBytesMByteArray mba)- {-# INLINE resizeMem #-}--instance (Typeable p, Prim e) => IsList (ByteArray p e) where- type Item (ByteArray p e) = e- fromList = fromListMem- fromListN n = fromListMemN_ (Count n)- toList = toListMem--instance Typeable p => IsString (ByteArray p Char) where- fromString = fromListMem--instance (Show e, Prim e) => Show (ByteArray p e) where- show = show . toListByteArray---toListByteArray :: Prim e => ByteArray p e -> [e]-toListByteArray = toListMem--castByteArray :: ByteArray p e' -> ByteArray p e-castByteArray = coerce--fromBytesByteArray :: Bytes p -> ByteArray p e-fromBytesByteArray = coerce--toBytesByteArray :: ByteArray p e -> Bytes p-toBytesByteArray = coerce--castMByteArray :: MByteArray p e' s -> MByteArray p e s-castMByteArray = coerce--fromMBytesMByteArray :: MBytes p s -> MByteArray p e s-fromMBytesMByteArray = coerce--toMBytesMByteArray :: MByteArray p e s -> MBytes p s-toMBytesMByteArray = coerce--sizeByteArray :: forall e p. Prim e => ByteArray p e -> Size-sizeByteArray = (coerce :: Count e -> Size) . countBytes . toBytesByteArray-{-# INLINE sizeByteArray #-}--getSizeMByteArray :: forall e p m s. (MonadPrim s m, Prim e) => MByteArray p e s -> m Size-getSizeMByteArray = fmap (coerce :: Count e -> Size) . getCountMBytes . toMBytesMByteArray-{-# INLINE getSizeMByteArray #-}--allocMByteArray ::- forall e p m s . (Typeable p, Prim e, MonadPrim s m) => Size -> m (MByteArray p e s)-allocMByteArray sz = fromMBytesMByteArray <$> allocMBytes (coerce sz :: Count e)-{-# INLINE allocMByteArray #-}--allocUnpinnedMByteArray :: forall e m s . (MonadPrim s m, Prim e) => Size -> m (MByteArray 'Inc e s)-allocUnpinnedMByteArray sz = fromMBytesMByteArray <$> allocUnpinnedMBytes (coerce sz :: Count e)-{-# INLINE allocUnpinnedMByteArray #-}--allocPinnedMByteArray :: forall e m s . (MonadPrim s m, Prim e) => Size -> m (MByteArray 'Pin e s)-allocPinnedMByteArray sz = fromMBytesMByteArray <$> allocPinnedMBytes (coerce sz :: Count e)-{-# INLINE allocPinnedMByteArray #-}--allocAlignedMByteArray ::- (MonadPrim s m, Prim e)- => Count e -- ^ Size in number of bytes- -> m (MByteArray 'Pin e s)-allocAlignedMByteArray = fmap fromMBytesMByteArray . allocAlignedMBytes-{-# INLINE allocAlignedMByteArray #-}--freezeMByteArray :: MonadPrim s m => MByteArray p e s -> m (ByteArray p e)-freezeMByteArray = fmap fromBytesByteArray . freezeMBytes . toMBytesMByteArray-{-# INLINE freezeMByteArray #-}--thawByteArray :: MonadPrim s m => ByteArray p e -> m (MByteArray p e s)-thawByteArray = fmap fromMBytesMByteArray . thawBytes . toBytesByteArray-{-# INLINE thawByteArray #-}---- | Shrink mutable bytes to new specified count of elements. The new count must be less--- than or equal to the current count as reported by `getCountMByteArray`.-shrinkMByteArray ::- forall e p m s. (MonadPrim s m, Prim e)- => MByteArray p e s- -> Size- -> m ()-shrinkMByteArray mba sz = shrinkMBytes (toMBytesMByteArray mba) (coerce sz :: Count e)-{-# INLINE shrinkMByteArray #-}----- | Attempt to resize mutable bytes in place.------ * New bytes might be allocated, with the copy of an old one.--- * Old references should not be kept around to allow GC to claim it--- * Old references should not be used to avoid undefined behavior-resizeMByteArray ::- forall e p m s. (MonadPrim s m, Prim e)- => MByteArray p e s- -> Size- -> m (MByteArray 'Inc e s)-resizeMByteArray mba sz =- fromMBytesMByteArray <$>- resizeMBytes (toMBytesMByteArray mba) (coerce sz :: Count e)-{-# INLINE resizeMByteArray #-}--reallocMByteArray ::- forall e p m s. (MonadPrim s m, Typeable p, Prim e)- => MByteArray p e s- -> Size- -> m (MByteArray p e s)-reallocMByteArray mba sz =- fromMBytesMByteArray <$>- reallocMBytes (toMBytesMByteArray mba) (coerce sz :: Count e)-{-# INLINABLE reallocMByteArray #-}---isPinnedByteArray :: ByteArray p e -> Bool-isPinnedByteArray (ByteArray b) = isPinnedBytes b-{-# INLINE isPinnedByteArray #-}--isPinnedMByteArray :: MByteArray p e s -> Bool-isPinnedMByteArray (MByteArray mb) = isPinnedMBytes mb-{-# INLINE isPinnedMByteArray #-}--readMByteArray :: (MonadPrim s m, Prim e) => MByteArray p e s -> Int -> m e-readMByteArray (MByteArray mb) = readOffMBytes mb . coerce-{-# INLINE readMByteArray #-}--writeMByteArray :: (MonadPrim s m, Prim e) => MByteArray p e s -> Int -> e -> m ()-writeMByteArray (MByteArray mb) o = writeOffMBytes mb (coerce o)-{-# INLINE writeMByteArray #-}----setMByteArray ::- (MonadPrim s m, Prim e)- => MByteArray p e s -- ^ Chunk of memory to fill- -> Int -- ^ Offset in number of elements- -> Size -- ^ Number of cells to fill- -> e -- ^ A value to fill the cells with- -> m ()-setMByteArray (MByteArray mb) off sz = setMBytes mb (coerce off) (coerce sz)-{-# INLINE setMByteArray #-}--copyByteArrayToMByteArray ::- (MonadPrim s m, Prim e)- => ByteArray p e- -> Int- -> MByteArray p e s- -> Int- -> Size- -> m ()-copyByteArrayToMByteArray ba srcOff mba dstOff sz =- copyMem ba (coerce srcOff) mba (coerce dstOff) (countAsProxy ba (coerce sz))-{-# INLINE copyByteArrayToMByteArray #-}--moveMByteArrayToMByteArray ::- forall e p m s. (MonadPrim s m, Prim e)- => MByteArray p e s- -> Int- -> MByteArray p e s- -> Int- -> Size- -> m ()-moveMByteArrayToMByteArray ba srcOff mba dstOff sz =- moveMem ba (coerce srcOff) mba (coerce dstOff) (coerce sz :: Count e)-{-# INLINE moveMByteArrayToMByteArray #-}------ toPtrByteArray :: ByteArray Pin e -> Ptr e--- toPtrByteArray (ByteArray ba#) = Ptr (byteArrayContents# ba#)--- {-# INLINE toPtrByteArray #-}---- toPtrMByteArray :: MByteArray Pin e s -> Ptr e--- toPtrMByteArray (MByteArray mba#) = Ptr (mutableByteArrayContents# mba#)--- {-# INLINE toPtrMByteArray #-}---- -- | Pointer access to immutable `ByteArray` should be for read only purposes, but it is--- -- not enforced. Any mutation will break referential transparency--- withPtrByteArray :: MonadPrim s m => ByteArray Pin e -> (Ptr e -> m b) -> m b--- withPtrByteArray b f = do--- res <- f (toPtrByteArray b)--- res <$ touch b--- {-# INLINE withPtrByteArray #-}---- -- | Same as `withPtrByteArray`, but is suitable for actions that don't terminate--- withNoHaltPtrByteArray :: MonadUnliftPrim s m => ByteArray Pin e -> (Ptr e -> m b) -> m b--- withNoHaltPtrByteArray b f = withAliveUnliftPrim b $ f (toPtrByteArray b)--- {-# INLINE withNoHaltPtrByteArray #-}---- withPtrMByteArray :: MonadPrim s m => MByteArray Pin e s -> (Ptr e -> m b) -> m b--- withPtrMByteArray mb f = do--- res <- f (toPtrMByteArray mb)--- res <$ touch mb--- {-# INLINE withPtrMByteArray #-}---- withNoHaltPtrMByteArray :: MonadUnliftPrim s m => MByteArray Pin e s -> (Ptr e -> m b) -> m b--- withNoHaltPtrMByteArray mb f = withAliveUnliftPrim mb $ f (toPtrMByteArray mb)--- {-# INLINE withNoHaltPtrMByteArray #-}----- -- -- | Check if two byte arrays refer to pinned memory and compare their pointers.--- -- isSameByteArray :: ByteArray p1 e -> ByteArray p2 e -> Bool--- -- isSameByteArray (ByteArray b1#) (ByteArray b2#) = isTrue# (isSameByteArray# b1# b2#)--- -- {-# INLINE[0] isSameByteArray #-}--- -- {-# RULES--- -- "isSamePinnedByteArray" isSameByteArray = isSamePinnedByteArray--- -- #-}---- -- -- | Perform pointer equality on pinned `ByteArray`.--- -- isSamePinnedByteArray :: ByteArray Pin e -> ByteArray Pin e -> Bool--- -- isSamePinnedByteArray pb e1 pb2 = toPtrByteArray pb e1 == toPtrByteArray pb e2--- -- {-# INLINE isSamePinnedByteArray #-}------ -- byteStringConvertError :: String -> a--- -- byteStringConvertError msg = error $ "Cannot convert 'ByteString'. " ++ msg--- -- {-# NOINLINE byteStringConvertError #-}-
src/Data/Prim/Memory/ByteString.hs view
@@ -1,3 +1,4 @@+{-# LANGUAGE CPP #-} {-# LANGUAGE DataKinds #-} {-# LANGUAGE MagicHash #-} -- |@@ -34,6 +35,7 @@ import Data.ByteString.Builder import Data.ByteString.Internal import Data.ByteString.Short.Internal+import qualified Data.ByteString as BS import qualified Data.ByteString.Lazy as BSL import Data.Prim import Foreign.Prim@@ -46,8 +48,9 @@ , allocMBytes , freezeMBytes , byteCountBytes+ , relaxPinnedBytes , toForeignPtrBytes- , fromForeignPtrBytes+ , castForeignPtrToBytes , byteStringConvertError ) @@ -55,13 +58,39 @@ newtype MByteString s = MByteString ByteString --- | /O(1)/ - Cast an immutable `Bytes` to an immutable `ByteString`+-- | /O(1)/ - Cast immutable `Bytes` to an immutable `ByteString` -- -- @since 0.1.0 toByteStringBytes :: Bytes 'Pin -> ByteString-toByteStringBytes b = PS (toForeignPtrBytes b) 0 (coerce (byteCountBytes b)) {-# INLINE toByteStringBytes #-}+toByteStringBytes b =+#if MIN_VERSION_bytestring(0,11,0)+ BS (toForeignPtrBytes b) (coerce (byteCountBytes b))+#else+ PS (toForeignPtrBytes b) 0 (coerce (byteCountBytes b))+#endif ++-- | /O(1)/ - Cast an immutable `ByteString` to immutable `Bytes`. Only unsliced+-- `ByteString`s that are backed by a `ForeignPtr` allocated on Haskell heap without+-- finilizers can be converted without copy.+--+-- @since 0.2.0+castByteStringBytes :: ByteString -> Either String (Bytes 'Pin)+#if MIN_VERSION_bytestring(0,11,0)+castByteStringBytes (BS fptr n) = do+#else+castByteStringBytes (PS fptr o n) = do+ unless (o == 0) sliceError+#endif+ b <- castForeignPtrToBytes fptr+ unless (unCount (byteCountBytes b) == n) sliceError+ Right b+ where+ sliceError = Left "ByteString was sliced"+{-# INLINE castByteStringBytes #-}++ -- | /O(1)/ - Cast an immutable `Bytes` to an immutable `ShortByteString` -- -- @since 0.1.0@@ -92,32 +121,43 @@ -- | /O(n)/ - Allocate `Bytes` and fill them with the contents of a lazy `BSL.ByteString` fromLazyByteStringBytes :: BSL.ByteString -> Bytes 'Pin-fromLazyByteStringBytes bsl =- case BSL.toStrict bsl of- PS fptr _ _ -> either byteStringConvertError id $ fromForeignPtrBytes fptr+fromLazyByteStringBytes = fromByteStringBytes . BSL.toStrict {-# INLINE fromLazyByteStringBytes #-} --- | /O(n)/ - Allocate `Bytes` and fill them with the contents of a strict `ByteString`+-- | /O(n)/ - Convert a strict `ByteString` to `Bytes`. fromByteStringBytes :: Typeable p => ByteString -> Bytes p-fromByteStringBytes bs@(PS _ _ n) =- runST $- withPtrByteString bs $ \ptr -> do- let c = Count n :: Count Word8- mb <- allocMBytes c- movePtrToMBytes ptr 0 mb 0 c- freezeMBytes mb+fromByteStringBytes bs =+ case castByteStringBytes bs of+ Right b -> relaxPinnedBytes b+ Left _ ->+ runST $+ withPtrByteString bs $ \ptr -> do+ let c = Count (BS.length bs) :: Count Word8+ mb <- allocMBytes c+ copyPtrToMBytes ptr 0 mb 0 c+ freezeMBytes mb {-# INLINE fromByteStringBytes #-} withPtrByteString :: MonadPrim s m => ByteString -> (Ptr a -> m b) -> m b-withPtrByteString (PS (ForeignPtr addr# ptrContents) (I# o#) _) f = do- r <- f (Ptr (addr# `plusAddr#` o#))+#if MIN_VERSION_bytestring(0,11,0)+withPtrByteString (BS (ForeignPtr addr# ptrContents) _) f = do+#else+withPtrByteString (PS (ForeignPtr addr'# ptrContents) (I# o#) _) f = do+ let addr# = addr'# `plusAddr#` o#+#endif+ r <- f (Ptr addr#) r <$ touch ptrContents {-# INLINE withPtrByteString #-} withNoHaltPtrByteString :: MonadUnliftPrim s m => ByteString -> (Ptr a -> m b) -> m b-withNoHaltPtrByteString (PS (ForeignPtr addr# ptrContents) (I# o#) _) f =- withAliveUnliftPrim ptrContents $ f (Ptr (addr# `plusAddr#` o#))+#if MIN_VERSION_bytestring(0,11,0)+withNoHaltPtrByteString (BS (ForeignPtr addr# ptrContents) _) f = do+#else+withNoHaltPtrByteString (PS (ForeignPtr addr'# ptrContents) (I# o#) _) f = do+ let addr# = addr'# `plusAddr#` o#+#endif+ withAliveUnliftPrim ptrContents $ f (Ptr addr#) {-# INLINE withNoHaltPtrByteString #-}
src/Data/Prim/Memory/Bytes.hs view
@@ -6,7 +6,6 @@ {-# LANGUAGE RankNTypes #-} {-# LANGUAGE ScopedTypeVariables #-} {-# LANGUAGE TypeFamilies #-}-{-# LANGUAGE TypeOperators #-} {-# LANGUAGE UnboxedTuples #-} -- | -- Module : Data.Prim.Memory.Bytes@@ -36,6 +35,8 @@ , isPinnedMBytes , toPinnedBytes , toPinnedMBytes+ , toInconclusiveBytes+ , toInconclusiveMBytes , relaxPinnedBytes , relaxPinnedMBytes , ensurePinnedBytes@@ -155,7 +156,6 @@ import Data.Prim import Data.Prim.Atomic import Data.Prim.Memory.Internal-import Data.Prim.Memory.Bytes.Internal import Foreign.Prim -- | Wrap `ByteArray#` into `Bytes`@@ -176,7 +176,6 @@ - -- | Check if two mutable bytes pointers refer to the same memory isSameMBytes :: MBytes p1 s -> MBytes p2 s -> Bool isSameMBytes (MBytes mb1#) (MBytes mb2#) = isTrue# (sameMutableByteArray# mb1# mb2#)@@ -188,17 +187,9 @@ ---- Pure --- -- This works exactly the same as `compareBytes` except it is implemented with FFI--- -- call instead of a primop. It will probably prove to be useless and will be removed in--- -- the future.--- memcmpBytes :: Prim e => Bytes p1 -> Off e -> Bytes p2 -> Off e -> Count e -> Ordering--- memcmpBytes (Bytes ba1#) off1 (Bytes ba2#) off2 c =--- toOrdering# (memcmpByteArray# ba1# (fromOff# off1) ba2# (fromOff# off2) (fromCount# c))--- {-# INLINE memcmpBytes #-}- compareBytes :: Prim e => Bytes p1 -> Off e -> Bytes p2 -> Off e -> Count e -> Ordering compareBytes (Bytes b1#) off1 (Bytes b2#) off2 c =- toOrdering# (compareByteArrays# b1# (fromOff# off1) b2# (fromOff# off2) (fromCount# c))+ toOrdering# (compareByteArrays# b1# (unOffBytes# off1) b2# (unOffBytes# off2) (unCountBytes# c)) {-# INLINE compareBytes #-} @@ -244,14 +235,14 @@ (MonadPrim s m, Prim e) => Bytes ps -> Off e -> MBytes pd s -> Off e -> Count e -> m () copyBytesToMBytes (Bytes src#) srcOff (MBytes dst#) dstOff c = prim_ $- copyByteArray# src# (fromOff# srcOff) dst# (fromOff# dstOff) (fromCount# c)+ copyByteArray# src# (unOffBytes# srcOff) dst# (unOffBytes# dstOff) (unCountBytes# c) {-# INLINE copyBytesToMBytes #-} moveMBytesToMBytes :: (MonadPrim s m, Prim e) => MBytes ps s-> Off e -> MBytes pd s -> Off e -> Count e -> m () moveMBytesToMBytes (MBytes src#) srcOff (MBytes dst#) dstOff c =- prim_ (copyMutableByteArray# src# (fromOff# srcOff) dst# (fromOff# dstOff) (fromCount# c))+ prim_ (copyMutableByteArray# src# (unOffBytes# srcOff) dst# (unOffBytes# dstOff) (unCountBytes# c)) {-# INLINE moveMBytesToMBytes #-} -- | Allocated memory is not cleared, so make sure to fill it in properly, otherwise you@@ -370,36 +361,27 @@ toListSlackBytes = toListSlackMem {-# INLINE toListSlackBytes #-} --- | Returns `EQ` if the full list did fit into the supplied memory chunk exactly.--- Otherwise it will return either `LT` if the list was smaller than allocated memory or--- `GT` if the list was bigger than the available memory and did not fit into `MBytes`.-loadListMBytes :: (MonadPrim s m, Prim e) => [e] -> MBytes p s -> m Ordering-loadListMBytes ys mb = do- (c, slack) <- getCountRemOfMBytes mb- loadListMemN (countAsProxy ys c) slack ys mb+-- | Same as `loadListMem`+loadListMBytes :: (Prim e, Typeable p, MonadPrim s m) => [e] -> MBytes p s -> m ([e], Count e)+loadListMBytes = loadListMem {-# INLINE loadListMBytes #-} -loadListMBytes_ :: (MonadPrim s m, Prim e) => [e] -> MBytes p s -> m ()-loadListMBytes_ ys mb = do- c <- getCountMBytes mb- loadListMemN_ (countAsProxy ys c) ys mb+-- | Same as `loadListMem_`+loadListMBytes_ :: (Prim e, Typeable p, MonadPrim s m) => [e] -> MBytes p s -> m ()+loadListMBytes_ = loadListMem_ {-# INLINE loadListMBytes_ #-} +-- | Same as `fromListZeroMemN_` fromListBytesN_ :: (Prim e, Typeable p) => Count e -> [e] -> Bytes p-fromListBytesN_ = fromListMemN_+fromListBytesN_ = fromListZeroMemN_ {-# INLINE fromListBytesN_ #-} --- | If the list is bigger than the supplied @`Count` a@ then `GT` ordering will be--- returned, along with the `Bytes` fully filled with the prefix of the list. On the other--- hand if the list is smaller than the supplied `Count`, `LT` with partially filled--- `Bytes` will returned. In the latter case expect some garbage at the end of the--- allocated memory, since no attempt is made to zero it out. Exact match obviously--- results in an `EQ`.+-- | Exactly like `fromListMemN`, but restricted to `Bytes`. fromListBytesN :: (Prim e, Typeable p) => Count e -> [e]- -> (Ordering, Bytes p)+ -> (Either [e] (Count e), Bytes p) fromListBytesN = fromListMemN {-# INLINE fromListBytesN #-} @@ -424,14 +406,7 @@ concatBytes = concatMem {-# INLINE concatBytes #-} -relaxPinnedBytes :: Bytes p -> Bytes 'Inc-relaxPinnedBytes = castPinnedBytes -relaxPinnedMBytes :: MBytes p e -> MBytes 'Inc e-relaxPinnedMBytes = castPinnedMBytes--- ensurePinnedBytes :: Bytes p -> Bytes 'Pin ensurePinnedBytes b = fromMaybe (convertMem b) (toPinnedBytes b) {-# INLINE ensurePinnedBytes #-}@@ -906,34 +881,34 @@ prefetchBytes0 :: (MonadPrim s m, Prim e) => Bytes p -> Off e -> m ()-prefetchBytes0 (Bytes b#) off = prim_ (prefetchByteArray0# b# (fromOff# off))+prefetchBytes0 (Bytes b#) off = prim_ (prefetchByteArray0# b# (unOffBytes# off)) {-# INLINE prefetchBytes0 #-} prefetchMBytes0 :: (MonadPrim s m, Prim e) => MBytes p s -> Off e -> m ()-prefetchMBytes0 (MBytes mb#) off = prim_ (prefetchMutableByteArray0# mb# (fromOff# off))+prefetchMBytes0 (MBytes mb#) off = prim_ (prefetchMutableByteArray0# mb# (unOffBytes# off)) {-# INLINE prefetchMBytes0 #-} prefetchBytes1 :: (MonadPrim s m, Prim e) => Bytes p -> Off e -> m ()-prefetchBytes1 (Bytes b#) off = prim_ (prefetchByteArray1# b# (fromOff# off))+prefetchBytes1 (Bytes b#) off = prim_ (prefetchByteArray1# b# (unOffBytes# off)) {-# INLINE prefetchBytes1 #-} prefetchMBytes1 :: (MonadPrim s m, Prim e) => MBytes p s -> Off e -> m ()-prefetchMBytes1 (MBytes mb#) off = prim_ (prefetchMutableByteArray1# mb# (fromOff# off))+prefetchMBytes1 (MBytes mb#) off = prim_ (prefetchMutableByteArray1# mb# (unOffBytes# off)) {-# INLINE prefetchMBytes1 #-} prefetchBytes2 :: (MonadPrim s m, Prim e) => Bytes p -> Off e -> m ()-prefetchBytes2 (Bytes b#) off = prim_ (prefetchByteArray2# b# (fromOff# off))+prefetchBytes2 (Bytes b#) off = prim_ (prefetchByteArray2# b# (unOffBytes# off)) {-# INLINE prefetchBytes2 #-} prefetchMBytes2 :: (MonadPrim s m, Prim e) => MBytes p s -> Off e -> m ()-prefetchMBytes2 (MBytes mb#) off = prim_ (prefetchMutableByteArray2# mb# (fromOff# off))+prefetchMBytes2 (MBytes mb#) off = prim_ (prefetchMutableByteArray2# mb# (unOffBytes# off)) {-# INLINE prefetchMBytes2 #-} prefetchBytes3 :: (MonadPrim s m, Prim e) => Bytes p -> Off e -> m ()-prefetchBytes3 (Bytes b#) off = prim_ (prefetchByteArray3# b# (fromOff# off))+prefetchBytes3 (Bytes b#) off = prim_ (prefetchByteArray3# b# (unOffBytes# off)) {-# INLINE prefetchBytes3 #-} prefetchMBytes3 :: (MonadPrim s m, Prim e) => MBytes p s -> Off e -> m ()-prefetchMBytes3 (MBytes mb#) off = prim_ (prefetchMutableByteArray3# mb# (fromOff# off))+prefetchMBytes3 (MBytes mb#) off = prim_ (prefetchMutableByteArray3# mb# (unOffBytes# off)) {-# INLINE prefetchMBytes3 #-}
src/Data/Prim/Memory/Bytes/Internal.hs view
@@ -1,7 +1,7 @@ {-# LANGUAGE BangPatterns #-}+{-# LANGUAGE CPP #-} {-# LANGUAGE DataKinds #-} {-# LANGUAGE FlexibleContexts #-}-{-# LANGUAGE KindSignatures #-} {-# LANGUAGE MagicHash #-} {-# LANGUAGE RankNTypes #-} {-# LANGUAGE RoleAnnotations #-}@@ -25,8 +25,13 @@ , isSamePinnedBytes , isPinnedBytes , isPinnedMBytes+ , castStateMBytes , castPinnedBytes , castPinnedMBytes+ , relaxPinnedBytes+ , relaxPinnedMBytes+ , toInconclusiveBytes+ , toInconclusiveMBytes , allocMBytes , allocPinnedMBytes , allocAlignedMBytes@@ -59,7 +64,8 @@ , withNoHaltPtrMBytes , toForeignPtrBytes , toForeignPtrMBytes- , fromForeignPtrBytes+ , castForeignPtrToBytes+ , onForeignPtrContents , byteStringConvertError ) where @@ -68,22 +74,26 @@ import Control.Prim.Monad.Unsafe import Data.Prim import Data.Prim.Class-import GHC.ForeignPtr import Data.Typeable import Foreign.Prim-+import GHC.ForeignPtr+import Unsafe.Coerce+#if MIN_VERSION_base(4,14,0)+import Data.IORef+#endif --- | In Haskell there is a distinction between pinned or unpinned memory.+-- | In GHC there is a distinction between pinned and unpinned memory. ----- Pinned memory is such, when allocated, it is guaranteed not to move throughout the+-- Pinned memory is such that when allocated, it is guaranteed not to move throughout the -- lifetime of a program. In other words the address pointer that refers to allocated--- bytes will not change until it gets garbage collected because it is no longer--- referenced by anything. Unpinned memory on the other hand can be moved around during--- GC, which helps to reduce memory fragmentation.+-- bytes will not change until the associated `ByteArray#` or `MutableByteArray#` is no+-- longer referenced anywhere in the program at which point it gets garbage collected. On+-- the other hand unpinned memory can be moved around during GC, which helps to reduce+-- memory fragmentation. -- -- Pinned/unpinnned choice during allocation is a bit of a lie, because when attempt is -- made to allocate memory as unpinned, but requested size is a bit more than a certain--- threashold (somewhere around 3KiB) it might still be allocated as pinned. Because of+-- threshold (somewhere around 3KiB) it might still be allocated as pinned. Because of -- that fact through out the "primal" universe there is a distinction between memory that -- is either @`Pin`ned@ or @`Inc`onclusive@. --@@ -91,15 +101,16 @@ -- `Data.Prim.Memory.Bytes.toPinnedMBytes` to get a conclusive type. -- -- @since 0.1.0-data Pinned = Pin | Inc+data Pinned+ = Pin -- ^ Pinned, which indicates that allocated memory will not move+ | Inc -- ^ Inconclusive, thus memory could be pinned or unpinned -- | An immutable region of memory which was allocated either as pinned or unpinned. -- -- Constructor is not exported for safety. Violating type level `Pinned` kind is very -- dangerous. Type safe constructor `Data.Prim.Memory.Bytes.fromByteArray#` and unwrapper -- `Data.Prim.Memory.Bytes.toByteArray#` should be used instead. As a backdoor, of course,--- the actual constructor is available in "Data.Prim.Memory.Internal" module and specially--- unsafe function `castPinnedBytes` was crafted.+-- the actual constructor is available from @Data.Prim.Memory.Internal@ data Bytes (p :: Pinned) = Bytes ByteArray# type role Bytes nominal @@ -126,7 +137,7 @@ compareByteOffBytes :: Prim e => Bytes p1 -> Off Word8 -> Bytes p2 -> Off Word8 -> Count e -> Ordering compareByteOffBytes (Bytes b1#) (Off (I# off1#)) (Bytes b2#) (Off (I# off2#)) c =- toOrdering# (compareByteArrays# b1# off1# b2# off2# (fromCount# c))+ toOrdering# (compareByteArrays# b1# off1# b2# off2# (unCountBytes# c)) {-# INLINE compareByteOffBytes #-} indexOffBytes :: Prim e => Bytes p -> Off e -> e@@ -164,7 +175,7 @@ allocUnpinnedMBytes :: (MonadPrim s m, Prim e) => Count e -> m (MBytes 'Inc s) allocUnpinnedMBytes c = prim $ \s ->- case newByteArray# (fromCount# c) s of+ case newByteArray# (unCountBytes# c) s of (# s', ba# #) -> (# s', MBytes ba# #) {-# INLINE allocUnpinnedMBytes #-} @@ -172,7 +183,7 @@ allocPinnedMBytes :: (MonadPrim s m, Prim e) => Count e -> m (MBytes 'Pin s) allocPinnedMBytes c = prim $ \s ->- case newPinnedByteArray# (fromCount# c) s of+ case newPinnedByteArray# (unCountBytes# c) s of (# s', ba# #) -> (# s', MBytes ba# #) {-# INLINE allocPinnedMBytes #-} @@ -183,7 +194,7 @@ allocAlignedMBytes c = prim $ \s -> case newAlignedPinnedByteArray#- (fromCount# c)+ (unCountBytes# c) (alignment# (proxy# :: Proxy# e)) s of (# s', ba# #) -> (# s', MBytes ba# #)@@ -221,13 +232,13 @@ copyByteOffBytesToMBytes :: (MonadPrim s m, Prim e) => Bytes ps -> Off Word8 -> MBytes pd s -> Off Word8 -> Count e -> m () copyByteOffBytesToMBytes (Bytes src#) (Off (I# srcOff#)) (MBytes dst#) (Off (I# dstOff#)) c =- prim_ $ copyByteArray# src# srcOff# dst# dstOff# (fromCount# c)+ prim_ $ copyByteArray# src# srcOff# dst# dstOff# (unCountBytes# c) {-# INLINE copyByteOffBytesToMBytes #-} moveByteOffMBytesToMBytes :: (MonadPrim s m, Prim e) => MBytes ps s-> Off Word8 -> MBytes pd s -> Off Word8 -> Count e -> m () moveByteOffMBytesToMBytes (MBytes src#) (Off (I# srcOff#)) (MBytes dst#) (Off (I# dstOff#)) c =- prim_ (copyMutableByteArray# src# srcOff# dst# dstOff# (fromCount# c))+ prim_ (copyMutableByteArray# src# srcOff# dst# dstOff# (unCountBytes# c)) {-# INLINE moveByteOffMBytesToMBytes #-} @@ -239,7 +250,7 @@ -- | Shrink mutable bytes to new specified count of elements. The new count must be less -- than or equal to the current count as reported by `getCountMBytes`. shrinkMBytes :: (MonadPrim s m, Prim e) => MBytes p s -> Count e -> m ()-shrinkMBytes (MBytes mb#) c = prim_ (shrinkMutableByteArray# mb# (fromCount# c))+shrinkMBytes (MBytes mb#) c = prim_ (shrinkMutableByteArray# mb# (unCountBytes# c)) {-# INLINE shrinkMBytes #-} @@ -252,7 +263,7 @@ (MonadPrim s m, Prim e) => MBytes p s -> Count e -> m (MBytes 'Inc s) resizeMBytes (MBytes mb#) c = prim $ \s ->- case resizeMutableByteArray# mb# (fromCount# c) s of+ case resizeMutableByteArray# mb# (unCountBytes# c) s of (# s', mb'# #) -> (# s', MBytes mb'# #) {-# INLINE resizeMBytes #-} @@ -274,12 +285,29 @@ Nothing -> castPinnedMBytes <$> resizeMBytes mb newByteCount {-# INLINABLE reallocMBytes #-} +castStateMBytes :: MBytes p s' -> MBytes p s+castStateMBytes = unsafeCoerce+ castPinnedBytes :: Bytes p' -> Bytes p castPinnedBytes (Bytes b#) = Bytes b# castPinnedMBytes :: MBytes p' s -> MBytes p s castPinnedMBytes (MBytes b#) = MBytes b# ++relaxPinnedBytes :: Bytes 'Pin -> Bytes p+relaxPinnedBytes = castPinnedBytes++relaxPinnedMBytes :: MBytes 'Pin e -> MBytes p e+relaxPinnedMBytes = castPinnedMBytes++toInconclusiveBytes :: Bytes p -> Bytes 'Inc+toInconclusiveBytes = castPinnedBytes++toInconclusiveMBytes :: MBytes p e -> MBytes 'Inc e+toInconclusiveMBytes = castPinnedMBytes++ -- | How many elements of type @a@ fits into bytes completely. In order to get a possible -- count of leftover bytes use `countRemBytes` countBytes :: Prim e => Bytes p -> Count e@@ -373,26 +401,54 @@ toForeignPtrMBytes :: MBytes 'Pin s -> ForeignPtr e toForeignPtrMBytes (MBytes mba#) =- ForeignPtr (byteArrayContents# (unsafeCoerce# mba#)) (PlainPtr (unsafeCoerce# mba#))+ ForeignPtr (mutableByteArrayContents# mba#) (PlainPtr (unsafeCoerce# mba#)) {-# INLINE toForeignPtrMBytes #-} --- | Discarding the `ForeignPtr` will trigger all if there are any associated--- Haskell finalizers.-fromForeignPtrBytes :: ForeignPtr e -> Either String (Bytes 'Pin)-fromForeignPtrBytes (ForeignPtr addr# content) =- case content of- PlainPtr mbaRW# -> checkConvert mbaRW#- MallocPtr mbaRW# _ -> checkConvert mbaRW#- _ -> Left "Cannot convert a C allocated pointer"+-- | This function will only cast a pointer that was allocated on Haskell heap and it is+-- cerain that the ForeignPtr has no finalizers associated with it.+castForeignPtrToBytes :: ForeignPtr e -> Either String (Bytes 'Pin)+castForeignPtrToBytes fp =+ unsafePerformIO $+ onForeignPtrContents fp checkConvert $ \_ ->+ pure (Left "Cannot convert a C allocated pointer") where- checkConvert mba# =- let !b@(Bytes ba#) = unsafePerformIO (freezeMBytes (MBytes mba#))- in if isTrue# (byteArrayContents# ba# `eqAddr#` addr#)- then Right b- else Left- "ForeignPtr does not point to the beginning of the associated MutableByteArray#"-{-# INLINE fromForeignPtrBytes #-}+ checkConvert addr# mba# checkFinalizers = do+ ba@(Bytes ba#) <- freezeMBytes (MBytes mba#)+ if isTrue# (byteArrayContents# ba# `eqAddr#` addr#)+ then do+ hasFinilizers <- checkFinalizers+ pure $+ if hasFinilizers+ then Left "MallocPtr has associated finalizers"+ else Right ba+ else pure $+ Left+ "ForeignPtr does not point to the beginning of the associated MutableByteArray#"+{-# INLINE castForeignPtrToBytes #-}+++onForeignPtrContents ::+ MonadPrim RW m+ => ForeignPtr e+ -> (Addr# -> MutableByteArray# RW -> m Bool -> m a)+ -> (Addr# -> m a)+ -> m a+onForeignPtrContents (ForeignPtr addr# contents) onHaskellPtr onCPtr =+ case contents of+ PlainPtr mbaRW# -> onHaskellPtr addr# mbaRW# (pure False)+#if MIN_VERSION_base(4,14,0)+ MallocPtr mbaRW# fref -> onHaskellPtr addr# mbaRW# $ do+ finilizers <- liftPrimBase $ readIORef fref+ pure $! case finilizers of+ NoFinalizers -> False+ HaskellFinalizers fs -> not $! null fs+ CFinalizers _ -> True -- impossible case, but nevertheless+#else+ MallocPtr mbaRW# _ -> onHaskellPtr addr# mbaRW# (pure True)+#endif+ PlainForeignPtr _ -> onCPtr addr#+{-# INLINE onForeignPtrContents #-} -- | Check if two byte arrays refer to pinned memory and compare their pointers.
src/Data/Prim/Memory/ForeignPtr.hs view
@@ -2,9 +2,9 @@ {-# LANGUAGE FlexibleContexts #-} {-# LANGUAGE FlexibleInstances #-} {-# LANGUAGE MagicHash #-}-{-# LANGUAGE UnboxedTuples #-} {-# LANGUAGE MultiParamTypeClasses #-} {-# LANGUAGE ScopedTypeVariables #-}+{-# LANGUAGE UnboxedTuples #-} -- | -- Module : Data.Prim.Bytes.ForeignPtr -- Copyright : (c) Alexey Kuleshevich 2020@@ -60,31 +60,19 @@ , toForeignPtrMBytes ) where -import Control.Prim.Monad-import Data.Prim-import Data.Prim.Class-import Data.Prim.Memory.ByteString-import Data.Prim.Memory.Bytes.Internal- ( Bytes- , MBytes(..)- , Pinned(..)- , toForeignPtrBytes- , toForeignPtrMBytes- , withNoHaltPtrBytes- , withNoHaltPtrMBytes- , withPtrBytes- , withPtrMBytes- )-import Foreign.Prim-import GHC.ForeignPtr- ( FinalizerEnvPtr- , FinalizerPtr- , ForeignPtr(..)- , ForeignPtrContents(..)- , castForeignPtr- , unsafeForeignPtrToPtr- )+import Control.Prim.Monad+import Data.Prim+import Data.Prim.Class+import Data.Prim.Memory.Bytes.Internal (Bytes, MBytes(..), Pinned(..),+ toForeignPtrBytes, toForeignPtrMBytes,+ withNoHaltPtrBytes, withNoHaltPtrMBytes,+ withPtrBytes, withPtrMBytes)+import Data.Prim.Memory.ByteString import qualified Foreign.ForeignPtr as GHC+import Foreign.Prim+import GHC.ForeignPtr (FinalizerEnvPtr, FinalizerPtr, ForeignPtr(..),+ ForeignPtrContents(..), castForeignPtr,+ unsafeForeignPtrToPtr) import qualified GHC.ForeignPtr as GHC @@ -102,19 +90,17 @@ withPtrAccess p action = toForeignPtr p >>= (`withForeignPtr` action) {-# INLINE withPtrAccess #-} - -- | See this GHC <https://gitlab.haskell.org/ghc/ghc/issues/18061 issue #18061> and- -- related to get more insight why this is needed.- withNoHaltPtrAccess :: (MonadUnliftPrim s m) => p -> (Ptr a -> m b) -> m b- withNoHaltPtrAccess p f = do- ForeignPtr addr# ptrContents <- toForeignPtr p- withAliveUnliftPrim ptrContents $ f (Ptr addr#)+ -- | See this GHC <https://gitlab.haskell.org/ghc/ghc/issues/17746 issue #17746> and+ -- related to it in order to get more insight why this is needed.+ withNoHaltPtrAccess :: MonadUnliftPrim s m => p -> (Ptr a -> m b) -> m b+ withNoHaltPtrAccess p action = toForeignPtr p >>= (`withNoHaltForeignPtr` action) {-# INLINE withNoHaltPtrAccess #-} instance PtrAccess s (ForeignPtr a) where toForeignPtr = pure . coerce {-# INLINE toForeignPtr #-} --- | Read-only access, but it is not enforced.+-- | Read-only access, but immutability is not enforced. instance PtrAccess s ByteString where toForeignPtr (PS ps s _) = pure (coerce ps `plusByteOffForeignPtr` Off s) {-# INLINE toForeignPtr #-}@@ -131,7 +117,7 @@ withNoHaltPtrAccess mbs = withNoHaltPtrByteString (coerce mbs) {-# INLINE withNoHaltPtrAccess #-} --- | Read-only access, but it is not enforced.+-- | Read-only access, but immutability is not enforced. instance PtrAccess s (Bytes 'Pin) where toForeignPtr = pure . toForeignPtrBytes {-# INLINE toForeignPtr #-}@@ -198,7 +184,7 @@ -- | Similar to `Foreign.ForeignPtr.mallocForeignPtrArray`, except instead of `Storable` we -- use `Prim`. mallocCountForeignPtr :: (MonadPrim RW m, Prim e) => Count e -> m (ForeignPtr e)-mallocCountForeignPtr = liftPrimBase . GHC.mallocForeignPtrBytes . fromCount+mallocCountForeignPtr = liftPrimBase . GHC.mallocForeignPtrBytes . unCountBytes -- | Just like `mallocCountForeignPtr`, but memory is also aligned according to `Prim` instance mallocCountForeignPtrAligned :: (MonadPrim RW m, Prim e) => Count e -> m (ForeignPtr e)@@ -252,7 +238,7 @@ mallocCountPlainForeignPtrAligned c = prim $ \s -> let a# = alignment# (proxy# :: Proxy# e)- in case newAlignedPinnedByteArray# (fromCount# c) a# s of+ in case newAlignedPinnedByteArray# (unCountBytes# c) a# s of (# s', mba# #) -> let addr# = mutableByteArrayContents# mba# in (# s', ForeignPtr addr# (PlainPtr (unsafeCoerce# mba#)) #)@@ -304,7 +290,7 @@ -- @since 0.1.0 plusOffForeignPtr :: Prim e => ForeignPtr e -> Off e -> ForeignPtr e plusOffForeignPtr (ForeignPtr addr# content) off =- ForeignPtr (addr# `plusAddr#` fromOff# off) content+ ForeignPtr (addr# `plusAddr#` unOffBytes# off) content {-# INLINE plusOffForeignPtr #-}
src/Data/Prim/Memory/Internal.hs view
@@ -2,979 +2,2356 @@ {-# LANGUAGE DataKinds #-} {-# LANGUAGE FlexibleContexts #-} {-# LANGUAGE FlexibleInstances #-}-{-# LANGUAGE KindSignatures #-}-{-# LANGUAGE MultiParamTypeClasses #-}-{-# LANGUAGE RankNTypes #-}-{-# LANGUAGE RoleAnnotations #-}-{-# LANGUAGE ScopedTypeVariables #-}-{-# LANGUAGE TypeFamilies #-}-{-# LANGUAGE TypeFamilyDependencies #-}-{-# LANGUAGE UndecidableInstances #-}-{-# OPTIONS_GHC -fno-warn-orphans #-}--- |--- Module : Data.Prim.Memory.Internal--- Copyright : (c) Alexey Kuleshevich 2020--- License : BSD3--- Maintainer : Alexey Kuleshevich <alexey@kuleshevi.ch>--- Stability : experimental--- Portability : non-portable----module Data.Prim.Memory.Internal- ( Bytes(..)- , MBytes(..)- , Pinned(..)- , module Data.Prim.Memory.Internal- ) where--import Control.Exception-import Data.List.NonEmpty (NonEmpty(..))-import Control.Monad.ST-import Control.Prim.Monad-import Control.Prim.Monad.Unsafe-import Data.Foldable as Foldable-import Data.Prim-import Data.Prim.Memory.Bytes.Internal- ( Bytes(..)- , MBytes(..)- , Pinned(..)- , allocMBytes- , reallocMBytes- , byteCountBytes- , compareByteOffBytes- , copyByteOffBytesToMBytes- , freezeMBytes- , getByteCountMBytes- , indexByteOffBytes- , indexOffBytes- , isSameBytes- , moveByteOffMBytesToMBytes- , readByteOffMBytes- , readOffMBytes- , setMBytes- , thawBytes- , writeByteOffMBytes- , writeOffMBytes- )-import Data.List as List-import Data.Prim.Memory.ByteString-import Data.Prim.Memory.ForeignPtr-import Data.Prim.Memory.Ptr-import Foreign.Prim-import Numeric (showHex)-import qualified Data.Semigroup as Semigroup-import qualified Data.Monoid as Monoid-import Data.Kind---class MemRead r where- byteCountMem :: r -> Count Word8-- indexOffMem :: Prim e => r -> Off e -> e-- indexByteOffMem :: Prim e => r -> Off Word8 -> e-- -- | Source and target can't refer to the same memory chunks- copyByteOffToMBytesMem ::- (MonadPrim s m, Prim e) => r -> Off Word8 -> MBytes p s -> Off Word8 -> Count e -> m ()-- -- | Source and target can't refer to the same memory chunks- copyByteOffToPtrMem ::- (MonadPrim s m, Prim e) => r -> Off Word8 -> Ptr e -> Off Word8 -> Count e -> m ()-- compareByteOffToPtrMem ::- (MonadPrim s m, Prim e) => r -> Off Word8 -> Ptr e -> Off Word8 -> Count e -> m Ordering-- compareByteOffToBytesMem ::- (MonadPrim s m, Prim e) => r -> Off Word8 -> Bytes p -> Off Word8 -> Count e -> m Ordering-- compareByteOffMem ::- (MemRead r', Prim e) => r' -> Off Word8 -> r -> Off Word8 -> Count e -> Ordering---- | Generalized memory allocation and pure/mutable state conversion.-class (MemRead (FrozenMem a), MemWrite a) => MemAlloc a where- type FrozenMem a = (fa :: Type) | fa -> a-- getByteCountMem :: MonadPrim s m => a s -> m (Count Word8)-- allocByteCountMem :: MonadPrim s m => Count Word8 -> m (a s)-- thawMem :: MonadPrim s m => FrozenMem a -> m (a s)-- freezeMem :: MonadPrim s m => a s -> m (FrozenMem a)-- resizeMem :: (MonadPrim s m, Prim e) => a s -> Count e -> m (a s)- resizeMem = defaultResizeMem---class MemWrite w where- readOffMem :: (MonadPrim s m, Prim e) => w s -> Off e -> m e-- readByteOffMem :: (MonadPrim s m, Prim e) => w s -> Off Word8 -> m e-- writeOffMem :: (MonadPrim s m, Prim e) => w s -> Off e -> e -> m ()-- writeByteOffMem :: (MonadPrim s m, Prim e) => w s -> Off Word8 -> e -> m ()-- -- | Source and target can be overlapping memory chunks- moveByteOffToMBytesMem ::- (MonadPrim s m, Prim e) => w s -> Off Word8 -> MBytes p s -> Off Word8 -> Count e -> m ()-- -- | Source and target can be overlapping memory chunks- moveByteOffToPtrMem ::- (MonadPrim s m, Prim e) => w s -> Off Word8 -> Ptr e -> Off Word8 -> Count e -> m ()-- copyByteOffMem ::- (MonadPrim s m, MemRead r, Prim e) => r -> Off Word8 -> w s -> Off Word8 -> Count e -> m ()-- moveByteOffMem ::- (MonadPrim s m, MemWrite w', Prim e) => w' s -> Off Word8 -> w s -> Off Word8 -> Count e -> m ()-- -- TODO: Potential feature for the future implementation. Will require extra function in `Prim`.- --setByteOffMem :: (MonadPrim s m, Prim e) => w s -> Off Word8 -> Count e -> e -> m ()-- -- | Write the same value into each cell starting at an offset.- setMem- :: (MonadPrim s m, Prim e)- => w s -- ^ Writable memory. Must have enough bytes, at least: (off+count)*(sizeOf e)- -> Off e -- ^ An offset into writable memory at which element setting should start.- -> Count e -- ^ Numer of cells to write the elemnt into- -> e -- ^ Element to write into all memory cells specified by offset and count. Even- -- if the count is @0@ this element might be still fully evaluated.- -> m ()---instance MemRead ByteString where- byteCountMem (PS _ _ c) = Count c- {-# INLINE byteCountMem #-}- indexOffMem bs i = unsafeInlineIO $ withPtrAccess bs (`readOffPtr` i)- {-# INLINE indexOffMem #-}- indexByteOffMem bs i = unsafeInlineIO $ withPtrAccess bs (`readByteOffPtr` i)- {-# INLINE indexByteOffMem #-}- copyByteOffToMBytesMem bs srcOff mb dstOff c =- withPtrAccess bs $ \srcPtr -> copyByteOffPtrToMBytes srcPtr srcOff mb dstOff c- {-# INLINE copyByteOffToMBytesMem #-}- copyByteOffToPtrMem bs srcOff dstPtr dstOff c =- withPtrAccess bs $ \srcPtr -> copyByteOffPtrToPtr srcPtr srcOff dstPtr dstOff c- {-# INLINE copyByteOffToPtrMem #-}- compareByteOffToPtrMem bs off1 ptr2 off2 c =- withPtrAccess bs $ \ptr1 -> pure $ compareByteOffPtrToPtr ptr1 off1 ptr2 off2 c- {-# INLINE compareByteOffToPtrMem #-}- compareByteOffToBytesMem bs off1 bytes off2 c =- withPtrAccess bs $ \ptr1 -> pure $ compareByteOffPtrToBytes ptr1 off1 bytes off2 c- {-# INLINE compareByteOffToBytesMem #-}- compareByteOffMem mem1 off1 bs off2 c =- unsafeInlineIO $ withPtrAccess bs $ \ptr2 -> compareByteOffToPtrMem mem1 off1 ptr2 off2 c- {-# INLINE compareByteOffMem #-}---instance MemAlloc MByteString where- type FrozenMem MByteString = ByteString- getByteCountMem (MByteString (PS _ _ c)) = pure $ Count c- {-# INLINE getByteCountMem #-}- allocByteCountMem c = do- fp <- mallocByteCountPlainForeignPtr c- pure $ MByteString (PS fp 0 (coerce c))- {-# INLINE allocByteCountMem #-}- thawMem bs = pure $ MByteString bs- {-# INLINE thawMem #-}- freezeMem (MByteString bs) = pure bs- {-# INLINE freezeMem #-}- resizeMem bsm@(MByteString (PS fp o n)) newc- | newn > n = defaultResizeMem bsm newc- | otherwise = pure $ MByteString (PS fp o newn)- where -- constant slice if we need to reduce the size- Count newn = toByteCount newc- {-# INLINE resizeMem #-}--instance MemWrite MByteString where- readOffMem (MByteString mbs) i = withPtrAccess mbs (`readOffPtr` i)- {-# INLINE readOffMem #-}- readByteOffMem (MByteString mbs) i = withPtrAccess mbs (`readByteOffPtr` i)- {-# INLINE readByteOffMem #-}- writeOffMem (MByteString mbs) i a = withPtrAccess mbs $ \ptr -> writeOffPtr ptr i a- {-# INLINE writeOffMem #-}- writeByteOffMem (MByteString mbs) i a = withPtrAccess mbs $ \ptr -> writeByteOffPtr ptr i a- {-# INLINE writeByteOffMem #-}- moveByteOffToPtrMem (MByteString fsrc) srcOff dstPtr dstOff c =- withPtrAccess fsrc $ \srcPtr -> moveByteOffPtrToPtr srcPtr srcOff dstPtr dstOff c- {-# INLINE moveByteOffToPtrMem #-}- moveByteOffToMBytesMem (MByteString fsrc) srcOff dst dstOff c =- withPtrAccess fsrc $ \srcPtr -> moveByteOffPtrToMBytes srcPtr srcOff dst dstOff c- {-# INLINE moveByteOffToMBytesMem #-}- copyByteOffMem src srcOff (MByteString fdst) dstOff c =- withPtrAccess fdst $ \dstPtr -> copyByteOffToPtrMem src srcOff dstPtr dstOff c- {-# INLINE copyByteOffMem #-}- moveByteOffMem src srcOff (MByteString fdst) dstOff c =- withPtrAccess fdst $ \dstPtr -> moveByteOffToPtrMem src srcOff dstPtr dstOff c- {-# INLINE moveByteOffMem #-}- setMem (MByteString mbs) off c a = withPtrAccess mbs $ \ptr -> setOffPtr ptr off c a- {-# INLINE setMem #-}---instance MemRead ShortByteString where- byteCountMem = byteCountMem . fromShortByteStringBytes- {-# INLINE byteCountMem #-}- indexOffMem sbs = indexOffMem (fromShortByteStringBytes sbs)- {-# INLINE indexOffMem #-}- indexByteOffMem sbs = indexByteOffMem (fromShortByteStringBytes sbs)- {-# INLINE indexByteOffMem #-}- copyByteOffToMBytesMem sbs = copyByteOffToMBytesMem (fromShortByteStringBytes sbs)- {-# INLINE copyByteOffToMBytesMem #-}- copyByteOffToPtrMem sbs = copyByteOffToPtrMem (fromShortByteStringBytes sbs)- {-# INLINE copyByteOffToPtrMem #-}- compareByteOffToPtrMem sbs = compareByteOffToPtrMem (fromShortByteStringBytes sbs)- {-# INLINE compareByteOffToPtrMem #-}- compareByteOffToBytesMem sbs = compareByteOffToBytesMem (fromShortByteStringBytes sbs)- {-# INLINE compareByteOffToBytesMem #-}- compareByteOffMem mem off1 sbs = compareByteOffMem mem off1 (fromShortByteStringBytes sbs)- {-# INLINE compareByteOffMem #-}---- | A wrapper that adds a phantom state token. It can be use with types that either--- doesn't have such state token or are designed to work in `IO` and therefore restricted--- to `RW`. Using this wrapper is very much unsafe, so make sure you know what you are--- doing.-newtype MemState a s = MemState { unMemState :: a }--instance MemWrite (MemState (ForeignPtr a)) where- readOffMem (MemState fptr) i = withForeignPtr fptr $ \ptr -> readOffPtr (castPtr ptr) i- {-# INLINE readOffMem #-}- readByteOffMem (MemState fptr) i =- withForeignPtr fptr $ \ptr -> readByteOffPtr (castPtr ptr) i- {-# INLINE readByteOffMem #-}- writeOffMem (MemState fptr) i a = withForeignPtr fptr $ \ptr -> writeOffPtr (castPtr ptr) i a- {-# INLINE writeOffMem #-}- writeByteOffMem (MemState fptr) i a =- withForeignPtr fptr $ \ptr -> writeByteOffPtr (castPtr ptr) i a- {-# INLINE writeByteOffMem #-}- moveByteOffToPtrMem (MemState fsrc) srcOff dstPtr dstOff c =- withForeignPtr fsrc $ \srcPtr -> moveByteOffPtrToPtr (castPtr srcPtr) srcOff dstPtr dstOff c- {-# INLINE moveByteOffToPtrMem #-}- moveByteOffToMBytesMem (MemState fsrc) srcOff dst dstOff c =- withForeignPtr fsrc $ \srcPtr -> moveByteOffPtrToMBytes (castPtr srcPtr) srcOff dst dstOff c- {-# INLINE moveByteOffToMBytesMem #-}- copyByteOffMem src srcOff (MemState fdst) dstOff c =- withForeignPtr fdst $ \dstPtr ->- copyByteOffToPtrMem src srcOff (castPtr dstPtr) dstOff c- {-# INLINE copyByteOffMem #-}- moveByteOffMem src srcOff (MemState fdst) dstOff c =- withForeignPtr fdst $ \dstPtr ->- moveByteOffToPtrMem src srcOff (castPtr dstPtr) dstOff c- {-# INLINE moveByteOffMem #-}- setMem (MemState fptr) off c a = withForeignPtr fptr $ \ptr -> setOffPtr (castPtr ptr) off c a- {-# INLINE setMem #-}--modifyFetchOldMem ::- (MemWrite w, MonadPrim s m, Prim b) => w s -> Off b -> (b -> b) -> m b-modifyFetchOldMem mem o f = modifyFetchOldMemM mem o (pure . f)-{-# INLINE modifyFetchOldMem #-}---modifyFetchNewMem ::- (MemWrite w, MonadPrim s m, Prim b) => w s -> Off b -> (b -> b) -> m b-modifyFetchNewMem mem o f = modifyFetchNewMemM mem o (pure . f)-{-# INLINE modifyFetchNewMem #-}---modifyFetchOldMemM ::- (MemWrite w, MonadPrim s m, Prim b) => w s -> Off b -> (b -> m b) -> m b-modifyFetchOldMemM mem o f = do- a <- readOffMem mem o- a <$ (writeOffMem mem o =<< f a)-{-# INLINE modifyFetchOldMemM #-}---modifyFetchNewMemM ::- (MemWrite w, MonadPrim s m, Prim b) => w s -> Off b -> (b -> m b) -> m b-modifyFetchNewMemM mem o f = do- a <- readOffMem mem o- a' <- f a- a' <$ writeOffMem mem o a'-{-# INLINE modifyFetchNewMemM #-}---defaultResizeMem ::- (Prim e, MemAlloc a, MonadPrim s m) => a s -> Count e -> m (a s)-defaultResizeMem mem c = do- let newByteCount = toByteCount c- oldByteCount <- getByteCountMem mem- if oldByteCount == newByteCount- then pure mem- else do- newMem <- allocByteCountMem newByteCount- newMem <$ moveMem mem 0 newMem 0 oldByteCount----- | Make @n@ copies of supplied region of memory into a contiguous chunk of memory.-cycleMemN :: (MemAlloc a, MemRead r) => Int -> r -> FrozenMem a-cycleMemN n r- | n <= 0 = emptyMem- | otherwise =- runST $ do- let bc@(Count chunk) = byteCountMem r- c@(Count c8) = Count n * bc- mem <- allocByteCountMem c- let go i = when (i < c8) $ copyByteOffMem r 0 mem (Off i) bc >> go (i + chunk)- go 0- freezeMem mem-{-# INLINE cycleMemN #-}----- | Chunk of empty memory.-emptyMem :: MemAlloc a => FrozenMem a-emptyMem = createMemST_ (0 :: Count Word8) (\_ -> pure ())-{-# INLINE emptyMem #-}---- | A region of memory that hold a single element.-singletonMem ::- forall e a. (MemAlloc a, Prim e)- => e- -> FrozenMem a-singletonMem a = createMemST_ (1 :: Count e) $ \mem -> writeOffMem mem 0 a-{-# INLINE singletonMem #-}---- | Allocate enough memory for number of elements. Memory is not initialized and may--- contain garbage. Use `allocZeroMem` if clean memory is needed.------ [Unsafe Count] Negative element count will result in unpredictable behavior------ @since 0.1.0-allocMem :: (MemAlloc a, MonadPrim s m, Prim e) => Count e -> m (a s)-allocMem n = allocByteCountMem (toByteCount n)-{-# INLINE allocMem #-}----- | Same as `allocMem`, but also use @memset@ to initialize all the new memory to zeros.------ [Unsafe Count] Negative element count will result in unpredictable behavior------ @since 0.1.0-allocZeroMem ::- (MemAlloc a, MonadPrim s m, Prim e) => Count e -> m (a s)-allocZeroMem n = do- m <- allocMem n- m <$ setMem m 0 (toByteCount n) (0 :: Word8)-{-# INLINE allocZeroMem #-}---createMemST :: (MemAlloc a, Prim e) => Count e -> (forall s . a s -> ST s b) -> (b, FrozenMem a)-createMemST n f = runST $ do- m <- allocMem n- res <- f m- i <- freezeMem m- pure (res, i)-{-# INLINE createMemST #-}--createMemST_ :: (MemAlloc a, Prim e) => Count e -> (forall s . a s -> ST s b) -> FrozenMem a-createMemST_ n f = runST (allocMem n >>= \m -> f m >> freezeMem m)-{-# INLINE createMemST_ #-}--createZeroMemST :: (MemAlloc a, Prim e) => Count e -> (forall s . a s -> ST s b) -> (b, FrozenMem a)-createZeroMemST n f = runST $ do- m <- allocZeroMem n- res <- f m- i <- freezeMem m- pure (res, i)-{-# INLINE createZeroMemST #-}--createZeroMemST_ :: (MemAlloc a, Prim e) => Count e -> (forall s . a s -> ST s b) -> FrozenMem a-createZeroMemST_ n f = runST (allocZeroMem n >>= \m -> f m >> freezeMem m)-{-# INLINE createZeroMemST_ #-}---copyMem ::- (MonadPrim s m, MemRead r, MemWrite w, Prim e)- => r -- ^ Source memory region- -> Off e -- ^ Offset into the source in number of elements- -> w s -- ^ Destination memory region- -> Off e -- ^ Offset into destination in number of elements- -> Count e -- ^ Number of elements to copy over- -> m ()-copyMem src srcOff dst dstOff = copyByteOffMem src (toByteOff srcOff) dst (toByteOff dstOff)-{-# INLINE copyMem #-}---moveMem ::- (MonadPrim s m, MemWrite w1, MemWrite w2, Prim e)- => w1 s -- ^ Source memory region- -> Off e -- ^ Offset into the source in number of elements- -> w2 s -- ^ Destination memory region- -> Off e -- ^ Offset into destination in number of elements- -> Count e -- ^ Number of elements to copy over- -> m ()-moveMem src srcOff dst dstOff = moveByteOffMem src (toByteOff srcOff) dst (toByteOff dstOff)-{-# INLINE moveMem #-}---appendMem :: (MemRead r1, MemRead r2, MemAlloc a) => r1 -> r2 -> FrozenMem a-appendMem r1 r2 =- createMemST_ (n1 + n2) $ \mem -> do- copyMem r1 0 mem 0 n1- copyMem r2 (coerce n1) mem (coerce n1) n2- where- n1 = byteCountMem r1- n2 = byteCountMem r2-{-# INLINABLE appendMem #-}--concatMem :: (MemRead r, MemAlloc a) => [r] -> FrozenMem a-concatMem xs = do- let c = Foldable.foldl' (\ !acc b -> acc + byteCountMem b) 0 xs- createMemST_ c $ \mb -> do- let load i b = do- let cb@(Count n) = byteCountMem b :: Count Word8- (i + Off n) <$ copyMem b 0 mb i cb- foldM_ load 0 xs-{-# INLINABLE concatMem #-}---thawCopyMem ::- (MemRead r, MemAlloc a, MonadPrim s m, Prim e) => r -> Off e -> Count e -> m (a s)-thawCopyMem a off c = do- mem <- allocMem c- mem <$ copyMem a off mem 0 c-{-# INLINE thawCopyMem #-}--freezeCopyMem ::- (MemAlloc a, MonadPrim s m, Prim e)- => a s- -> Off e- -> Count e- -> m (FrozenMem a)-freezeCopyMem mem off c = freezeMem mem >>= \r -> thawCopyMem r off c >>= freezeMem-{-# INLINE freezeCopyMem #-}---thawCloneMem :: (MemRead r, MemAlloc a, MonadPrim s m) => r -> m (a s)-thawCloneMem a = thawCopyMem a 0 (byteCountMem a)-{-# INLINE thawCloneMem #-}--freezeCloneMem :: (MemAlloc a, MonadPrim s m) => a s -> m (FrozenMem a)-freezeCloneMem = freezeMem >=> thawCloneMem >=> freezeMem-{-# INLINE freezeCloneMem #-}---- | /O(n)/ - Convert a read-only memory region into a newly allocated other type of--- memory region------ >>> import Data.ByteString--- >>> bs = pack [0x10 .. 0x20]--- >>> bs--- "\DLE\DC1\DC2\DC3\DC4\NAK\SYN\ETB\CAN\EM\SUB\ESC\FS\GS\RS\US "--- >>> convertMem bs :: Bytes 'Inc--- [0x10,0x11,0x12,0x13,0x14,0x15,0x16,0x17,0x18,0x19,0x1a,0x1b,0x1c,0x1d,0x1e,0x1f,0x20]------ @since 0.1.0-convertMem :: (MemRead r, MemAlloc a) => r -> FrozenMem a-convertMem a = runST $ thawCloneMem a >>= freezeMem-{-# INLINE convertMem #-}---- | Figure out how many elements can fit into the region of memory. It is possible that--- there is a remainder of bytes left, see `countRemMem` for getting that too.------ ====__Examples__------ >>> b = fromListMem [0 .. 5 :: Word8] :: Bytes 'Pin--- >>> b--- [0x00,0x01,0x02,0x03,0x04,0x05]--- >>> countMem b :: Count Word16--- Count {unCount = 3}--- >>> countMem b :: Count Word32--- Count {unCount = 1}------ @since 0.1.0-countMem ::- forall e r. (MemRead r, Prim e)- => r -- ^ Read-only memory type- -> Count e-countMem = fromByteCount . byteCountMem-{-# INLINE countMem #-}---- | Compute how many elements and a byte size remainder that can fit into the region of memory.------ ====__Examples__------ >>> b = fromListMem [0 .. 5 :: Word8] :: Bytes 'Pin--- >>> b--- [0x00,0x01,0x02,0x03,0x04,0x05]--- >>> countRemMem @Word16 b--- (Count {unCount = 3},0)--- >>> countRemMem @Word32 b--- (Count {unCount = 1},2)------ @since 0.1.0-countRemMem :: forall e r. (MemRead r, Prim e) => r -> (Count e, Count Word8)-countRemMem = fromByteCountRem . byteCountMem-{-# INLINE countRemMem #-}--getCountMem :: (MemAlloc r, MonadPrim s m, Prim e) => r s -> m (Count e)-getCountMem = fmap (fromByteCount . coerce) . getByteCountMem-{-# INLINE getCountMem #-}---getCountRemMem :: (MemAlloc r, MonadPrim s m, Prim e) => r s -> m (Count e, Count Word8)-getCountRemMem = fmap (fromByteCountRem . coerce) . getByteCountMem-{-# INLINE getCountRemMem #-}---clone :: (MemAlloc r, MonadPrim s m) => r s -> m (r s)-clone mb = do- n <- getByteCountMem mb- mb' <- allocMem n- mb' <$ moveMem mb 0 mb' 0 n-{-# INLINE clone #-}--eqMem :: (MemRead r1, MemRead r2) => r1 -> r2 -> Bool-eqMem b1 b2 = n == byteCountMem b2 && compareByteOffMem b1 0 b2 0 n == EQ- where- n = byteCountMem b1-{-# INLINE eqMem #-}---- | Compare two regions of memory byte-by-byte. It will return `EQ` whenever both regions--- are exactly the same and `LT` or `GT` as soon as the first byte is reached that is less--- than or greater than respectfully in the first region when compared to the second--- one. It is safe for both regions to refer to the same part of memory, since this is a--- pure function and both regions of memory are read-only.-compareMem ::- (MemRead r1, MemRead r2, Prim e)- => r1 -- ^ First region of memory- -> Off e -- ^ Offset in number of elements into the first region- -> r2 -- ^ Second region of memory- -> Off e -- ^ Offset in number of elements into the second region- -> Count e -- ^ Number of elements to compare- -> Ordering-compareMem r1 off1 r2 off2 = compareByteOffMem r1 (toByteOff off1) r2 (toByteOff off2)-{-# INLINE compareMem #-}---- | It is only guaranteed to convert the whole memory to a list whenever the size of--- allocated memory is exactly divisible by the size of the element, otherwise there will--- be some slack left unaccounted for.-toListMem :: (MemRead r, Prim e) => r -> [e]-toListMem ba = build (\ c n -> foldrCountMem (countMem ba) c n ba)-{-# INLINE toListMem #-}-{-# SPECIALIZE toListMem :: Prim e => Bytes p -> [e] #-}---- | Same as `toListMem`, except if there is some slack at the end of the memory that--- didn't fit in a list it will be returned as a list of bytes------ ====__Examples__------ >>> import Data.Word--- >>> :set -XDataKinds--- >>> a = fromListMem [0 .. 10 :: Word8] :: Bytes 'Pin--- >>> a--- [0x00,0x01,0x02,0x03,0x04,0x05,0x06,0x07,0x08,0x09,0x0a]--- >>> toListSlackMem a :: ([Word8], [Word8])--- ([0,1,2,3,4,5,6,7,8,9,10],[])--- >>> toListSlackMem a :: ([Word16], [Word8])--- ([256,770,1284,1798,2312],[10])--- >>> toListSlackMem a :: ([Word32], [Word8])--- ([50462976,117835012],[8,9,10])--- >>> toListSlackMem a :: ([Word64], [Word8])--- ([506097522914230528],[8,9,10])------ @since 0.1.0-toListSlackMem ::- forall e r. (MemRead r, Prim e)- => r- -> ([e], [Word8])-toListSlackMem mem =- (build (\c n -> foldrCountMem k c n mem), getSlack (k8 + r8) [])- where- (k, Count r8) = countRemMem mem- Count k8 = toByteCount k- getSlack i !acc- | i == k8 = acc- | otherwise =- let i' = i - 1- in getSlack i' (indexByteOffMem mem (Off i') : acc)-{-# INLINABLE toListSlackMem #-}---- | Right fold that is useful for converting to list while tapping into list fusion.-foldrCountMem :: (MemRead r, Prim e) => Count e -> (e -> b -> b) -> b -> r -> b-foldrCountMem (Count k) c nil bs = go 0- where- go i- | i == k = nil- | otherwise =- let !v = indexOffMem bs (Off i)- in v `c` go (i + 1)-{-# INLINE[0] foldrCountMem #-}---loadListMemN ::- (MemWrite r, MonadPrim s m, Prim e)- => Count e- -> Count Word8- -> [e]- -> r s- -> m Ordering-loadListMemN (Count n) (Count slack) ys mb = do- let go [] !i = pure (compare i n <> compare 0 slack)- go (x:xs) !i- | i < n = writeOffMem mb (Off i) x >> go xs (i + 1)- | otherwise = pure GT- go ys 0-{-# INLINABLE loadListMemN #-}--loadListMemN_ :: (MemWrite r, MonadPrim s m, Prim e) => Count e -> [e] -> r s -> m ()-loadListMemN_ (Count n) ys mb =- let go [] _ = pure ()- go (x:xs) i = when (i < n) $ writeOffMem mb (Off i) x >> go xs (i + 1)- in go ys 0-{-# INLINABLE loadListMemN_ #-}---- | Returns `EQ` if the full list did fit into the supplied memory chunk exactly.--- Otherwise it will return either `LT` if the list was smaller than allocated memory or--- `GT` if the list was bigger than the available memory and did not fit into `MBytes`.-loadListMem :: (MonadPrim s m, MemAlloc r, Prim e) => [e] -> r s -> m Ordering-loadListMem ys mb = do- (c, slack) <- getCountRemMem mb- loadListMemN (countAsProxy ys c) slack ys mb-{-# INLINE loadListMem #-}--loadListMem_ :: (MonadPrim s m, MemAlloc r, Prim e) => [e] -> r s -> m ()-loadListMem_ ys mb = do- c <- getCountMem mb- loadListMemN_ (countAsProxy ys c) ys mb-{-# INLINE loadListMem_ #-}---fromListMemN :: (MemAlloc a, Prim e) => Count e -> [e] -> (Ordering, FrozenMem a)-fromListMemN n xs = createMemST n (loadListMemN n 0 xs)-{-# INLINE fromListMemN #-}--fromListMemN_ :: (MemAlloc a, Prim e) => Count e -> [e] -> FrozenMem a-fromListMemN_ !n xs = createMemST_ n (loadListMemN_ n xs)-{-# INLINE fromListMemN_ #-}--fromListMem :: (MemAlloc a, Prim e) => [e] -> FrozenMem a-fromListMem xs = fromListMemN_ (countAsProxy xs (coerce (length xs))) xs-{-# INLINE fromListMem #-}----- | Load a list of bytes into a newly allocated memory region. Equivalent to--- `Data.ByteString.pack` for `Data.ByteString.ByteString`------ ====__Examples__------ >>> fromByteListMem [0..10] :: Bytes 'Pin--- [0x00,0x01,0x02,0x03,0x04,0x05,0x06,0x07,0x08,0x09,0x0a]------ @since 0.1.0-fromByteListMem :: MemAlloc a => [Word8] -> FrozenMem a-fromByteListMem = fromListMem-{-# INLINE fromByteListMem #-}---- | Convert a memory region to a list of bytes. Equivalent to `Data.ByteString.unpack`--- for `Data.ByteString.ByteString`------ >>> toByteListMem (fromByteListMem [0..10] :: Bytes 'Pin)--- [0,1,2,3,4,5,6,7,8,9,10]------ @since 0.1.0-toByteListMem :: MemAlloc a => FrozenMem a -> [Word8]-toByteListMem = toListMem-{-# INLINE toByteListMem #-}---mapByteMem :: (MemRead r, MemAlloc a, Prim e) => (Word8 -> e) -> r -> FrozenMem a-mapByteMem f = mapByteOffMem (const f)---- | Map an index aware function over memory region------ >>> a = fromListMem [1 .. 10 :: Word8] :: Bytes 'Inc--- >>> a--- [0x01,0x02,0x03,0x04,0x05,0x06,0x07,0x08,0x09,0x0a]--- >>> imapMem (\i e -> (fromIntegral i :: Int8, e + 0xf0)) a :: Bytes 'Pin--- [0x00,0xf1,0x01,0xf2,0x02,0xf3,0x03,0xf4,0x04,0xf5,0x05,0xf6,0x06,0xf7,0x07,0xf8,0x08,0xf9,0x09,0xfa]------ @since 0.1.0-mapByteOffMem ::- (MemRead r, MemAlloc a, Prim e) => (Off Word8 -> Word8 -> e) -> r -> FrozenMem a-mapByteOffMem f r = runST $ mapByteOffMemM (\i -> pure . f i) r---- @since 0.1.0-mapByteMemM ::- (MemRead r, MemAlloc a, MonadPrim s m, Prim e)- => (Word8 -> m e)- -> r- -> m (FrozenMem a)-mapByteMemM f = mapByteOffMemM (const f)----- @since 0.1.0-mapByteOffMemM ::- (MemRead r, MemAlloc a, MonadPrim s m, Prim e)- => (Off Word8 -> Word8 -> m e)- -> r- -> m (FrozenMem a)-mapByteOffMemM f r = do- let bc@(Count n) = byteCountMem r- c = countAsProxy (f 0 0) (Count n)- mem <- allocMem c- _ <- forByteOffMemM_ r 0 bc f- -- let go i =- -- when (i < n) $ do- -- f i (indexByteOffMem r (Off i)) >>=- -- writeOffMem mem (offAsProxy c (Off i))- -- go (i + 1)- -- go 0- freezeMem mem----- | Iterate over a region of memory-forByteOffMemM_ ::- (MemRead r, MonadPrim s m, Prim e)- => r- -> Off Word8- -> Count e- -> (Off Word8 -> e -> m b)- -> m (Off Word8)-forByteOffMemM_ r (Off byteOff) c f =- let n = coerce (toByteCount c) + byteOff- Count k = byteCountProxy c- go i- | i < n = f (Off i) (indexByteOffMem r (Off i)) >> go (i + k)- | otherwise = pure $ Off i- in go byteOff--loopShortM :: Monad m => Int -> (Int -> a -> Bool) -> (Int -> Int) -> a -> (Int -> a -> m a) -> m a-loopShortM !startAt condition increment !initAcc f = go startAt initAcc- where- go !step !acc- | condition step acc = f step acc >>= go (increment step)- | otherwise = pure acc-{-# INLINE loopShortM #-}--loopShortM' :: Monad m => Int -> (Int -> a -> m Bool) -> (Int -> Int) -> a -> (Int -> a -> m a) -> m a-loopShortM' !startAt condition increment !initAcc f = go startAt initAcc- where- go !step !acc =- condition step acc >>= \cont ->- if cont- then f step acc >>= go (increment step)- else pure acc-{-# INLINE loopShortM' #-}---- -- | Iterate over a region of memory--- loopMemM_ ::--- (MemRead r, MonadPrim s m, Prim e)--- => r--- -> Off Word8--- -> Count e--- -> (Count Word8 -> a -> Bool)--- -> (Off Word8 -> e -> m b)--- -> m (Off Word8)--- foldlByteOffMemM_ r (Off byteOff) c f =--- loopShortM byteOff (\i -> f (coerce i))--- let n = coerce (toByteCount c) + byteOff--- Count k = byteCountProxy c--- go i--- | i < n = f (Off i) (indexByteOffMem r (Off i)) >> go (i + k)--- | otherwise = pure $ Off i--- in go byteOff---data MemView a = MemView- { mvOffset :: {-# UNPACK #-} !(Off Word8)- , mvCount :: {-# UNPACK #-} !(Count Word8)- , mvMem :: !a- }--data MMemView a s = MMemView- { mmvOffset :: {-# UNPACK #-} !(Off Word8)- , mmvCount :: {-# UNPACK #-} !(Count Word8)- , mmvMem :: !(a s)- }--izipWithByteOffMemM_ ::- (MemRead r1, MemRead r2, MonadPrim s m, Prim e)- => r1- -> Off Word8- -> r2- -> Off Word8- -> Count e- -> (Off Word8 -> e -> Off Word8 -> e -> m b)- -> m (Off Word8)-izipWithByteOffMemM_ r1 (Off byteOff1) r2 off2 c f =- let n = coerce (toByteCount c) + byteOff1- Count k = byteCountProxy c- go i- | i < n =- let o1 = Off i- o2 = Off i + off2- in f o1 (indexByteOffMem r1 o1) o2 (indexByteOffMem r2 o2) >>- go (i + k)- | otherwise = pure $ Off i- in go byteOff1---izipWithOffMemM_ ::- (MemRead r1, MemRead r2, MonadPrim s m, Prim e1, Prim e2)- => r1- -> Off e1- -> r2- -> Off e2- -> Int- -> (Off e1 -> e1 -> Off e2 -> e2 -> m b)- -> m ()-izipWithOffMemM_ r1 off1 r2 off2 nc f =- let n = nc + coerce off1- go o1@(Off i) o2 =- when (i < n) $- f o1 (indexOffMem r1 o1) o2 (indexOffMem r2 o2) >> go (o1 + 1) (o2 + 1)- in go off1 off2----- class Mut f => MFunctor f where--- mmap :: (Elt f a, Elt f b, MonadPrim s m) => (a -> b) -> f a s -> m (f b s)---- class Mut f => MTraverse f where--- mmapM :: (Elt f a, Elt f b, MonadPrim s m) => (a -> m b) -> f a s -> m (f b s)---- class MFunctor f => MApplicative f where--- pureMut :: (Elt f a, MonadPrim s m) => a -> m (f a s)--- liftMut ::--- (Elt f a, Elt f b, Elt f c, MonadPrim s m) => (a -> b -> m c) -> f a s -> f b s -> m (f c s)---- class MApplicative f => MMonad f where--- bindMut ::--- (Elt f a, Elt f b, MonadPrim s m) => f a s -> (a -> m b) -> f b s -> m (f c s)---- instance MFunctor MAddr where--- mmap f maddr = do--- Count n <- getCountMAddr maddr--- maddr' <- allocMAddr (Count n)--- let go i =--- when (i < n) $ do--- writeOffMAddr maddr' (Off i) . f =<< readOffMAddr maddr (Off i)--- go (i + 1)--- maddr' <$ go 0---- instance MTraverse MAddr where--- mmapM f maddr = do--- Count n <- getCountMAddr maddr--- maddr' <- allocMAddr (Count n)--- let go i =--- when (i < n) $ do--- writeOffMAddr maddr' (Off i) =<< f =<< readOffMAddr maddr (Off i)--- go (i + 1)--- maddr' <$ go 0------------------------- Bytes orphans ------------------------instance MemRead (Bytes p) where- byteCountMem = byteCountBytes- {-# INLINE byteCountMem #-}- indexOffMem = indexOffBytes- {-# INLINE indexOffMem #-}- indexByteOffMem = indexByteOffBytes- {-# INLINE indexByteOffMem #-}- copyByteOffToMBytesMem = copyByteOffBytesToMBytes- {-# INLINE copyByteOffToMBytesMem #-}- copyByteOffToPtrMem = copyByteOffBytesToPtr- {-# INLINE copyByteOffToPtrMem #-}- compareByteOffToPtrMem bytes1 off1 ptr2 off2 c =- pure $ compareByteOffBytesToPtr bytes1 off1 ptr2 off2 c- {-# INLINE compareByteOffToPtrMem #-}- compareByteOffToBytesMem bytes1 off1 bytes2 off2 c =- pure $ compareByteOffBytes bytes1 off1 bytes2 off2 c- {-# INLINE compareByteOffToBytesMem #-}- compareByteOffMem mem1 off1 bs off2 c =- unsafeInlineIO $ compareByteOffToBytesMem mem1 off1 bs off2 c- {-# INLINE compareByteOffMem #-}--instance Typeable p => MemAlloc (MBytes p) where- type FrozenMem (MBytes p) = Bytes p- getByteCountMem = getByteCountMBytes- {-# INLINE getByteCountMem #-}- allocByteCountMem = allocMBytes- {-# INLINE allocByteCountMem #-}- thawMem = thawBytes- {-# INLINE thawMem #-}- freezeMem = freezeMBytes- {-# INLINE freezeMem #-}- resizeMem = reallocMBytes- {-# INLINE resizeMem #-}--instance MemWrite (MBytes p) where- readOffMem = readOffMBytes- {-# INLINE readOffMem #-}- readByteOffMem = readByteOffMBytes- {-# INLINE readByteOffMem #-}- writeOffMem = writeOffMBytes- {-# INLINE writeOffMem #-}- writeByteOffMem = writeByteOffMBytes- {-# INLINE writeByteOffMem #-}- moveByteOffToPtrMem = moveByteOffMBytesToPtr- {-# INLINE moveByteOffToPtrMem #-}- moveByteOffToMBytesMem = moveByteOffMBytesToMBytes- {-# INLINE moveByteOffToMBytesMem #-}- moveByteOffMem = moveByteOffToMBytesMem- {-# INLINE moveByteOffMem #-}- copyByteOffMem = copyByteOffToMBytesMem- {-# INLINE copyByteOffMem #-}- setMem = setMBytes- {-# INLINE setMem #-}---instance Show (Bytes p) where- show b =- Foldable.foldr' ($) "]" $- ('[' :) : List.intersperse (',' :) (map (("0x" ++) .) (showsHexMem b))--instance Typeable p => IsList (Bytes p) where- type Item (Bytes p) = Word8- fromList = fromListMem- fromListN n = fromListMemN_ (Count n)- toList = toListMem--instance Eq (Bytes p) where- b1 == b2 = isSameBytes b1 b2 || eqMem b1 b2--instance Ord (Bytes p) where- compare b1 b2 =- compare n (byteCountBytes b2) <> compareByteOffBytes b1 0 b2 0 n- where- n = byteCountBytes b1--instance Typeable p => Semigroup.Semigroup (Bytes p) where- (<>) = appendMem- sconcat (x :| xs) = concatMem (x:xs)- stimes i = cycleMemN (fromIntegral i)--instance Typeable p => Monoid.Monoid (Bytes p) where- mappend = appendMem- mconcat = concatMem- mempty = emptyMem----- | A list of `ShowS` that covert bytes to base16 encoded strings. Each element of the list--- is a function that will convert one byte.------ >>> mb <- newPinnedMBytes (Count 5 :: Count Int)--- >>> mapM_ (\i -> writeOffMBytes mb (pred i) i) [1 .. 5]--- >>> foldr ($) "" . showsBytesHex <$> freezeMBytes mb--- "01000000000000000200000000000000030000000000000004000000000000000500000000000000"----showsHexMem :: MemRead r => r -> [ShowS]-showsHexMem b = map toHex (toListMem b :: [Word8])- where- toHex b8 =- (if b8 <= 0x0f- then ('0' :)- else id) .- showHex b8---- | Ensure that memory is filled with zeros before and after it is used.-withScrubbedMem ::- (MonadUnliftPrim RW m, Prim e, MemAlloc mem)- => Count e- -> (mem RW -> m a)- -> m a-withScrubbedMem c f = do- mem <- allocZeroMem c- f mem `finallyPrim` setMem mem 0 (toByteCount c) 0- where- finallyPrim m1 m2 = withRunInPrimBase $ \run -> finally (run m1) (run m2)+{-# LANGUAGE MultiParamTypeClasses #-}+{-# LANGUAGE RankNTypes #-}+{-# LANGUAGE RoleAnnotations #-}+{-# LANGUAGE ScopedTypeVariables #-}+{-# LANGUAGE TypeFamilyDependencies #-}+{-# LANGUAGE UndecidableInstances #-}+{-# OPTIONS_GHC -fno-warn-orphans #-}+{-# OPTIONS_HADDOCK hide, not-home #-}+-- |+-- Module : Data.Prim.Memory.Internal+-- Copyright : (c) Alexey Kuleshevich 2020+-- License : BSD3+-- Maintainer : Alexey Kuleshevich <alexey@kuleshevi.ch>+-- Stability : experimental+-- Portability : non-portable+--+module Data.Prim.Memory.Internal+ ( module Data.Prim.Memory.Internal+ , module Data.Prim.Memory.Bytes.Internal+ ) where++import Control.Exception+import Control.Monad.ST+import Control.Prim.Monad+import Control.Prim.Monad.Unsafe+import qualified Data.ByteString as BS+import Data.Foldable as Foldable+import Data.Kind+import Data.List as List+import Data.List.NonEmpty (NonEmpty(..))+import qualified Data.Monoid as Monoid+import Data.Prim+import Data.Prim.Memory.Bytes.Internal+import Data.Prim.Memory.ByteString+import Data.Prim.Memory.ForeignPtr+import Data.Prim.Memory.Ptr+import qualified Data.Semigroup as Semigroup+import qualified Data.Prim.Memory.Text as T+import Foreign.Prim+import Numeric (showHex)++-- | Type class that can be implemented for an immutable data type that provides+-- read-only direct access to memory+class MemRead mr where++ -- | Number of bytes allocated by the data type available for reading.+ --+ -- ====__Example__+ --+ -- >>> :set -XDataKinds+ -- >>> import Data.Prim.Memory+ -- >>> byteCountMem (fromByteListMem [1,2,3] :: Bytes 'Inc)+ -- Count {unCount = 3}+ --+ -- @since 0.1.0+ byteCountMem :: mr -> Count Word8++ -- | Read an element with an offset in number of elements, rather than bytes as is the+ -- case with `indexByteOffMem`.+ --+ -- [Unsafe] Bounds are not checked. When precondition for @off@ argument is violated the+ -- result is either unpredictable output or failure with a segfault.+ --+ -- @since 0.1.0+ indexOffMem :: Prim e+ => mr -- ^ /memRead/ - Memory to read an element from+ -> Off e+ -- ^ /off/ - Offset in number of elements from the beginning of @memRead@+ --+ -- /__Preconditions:__/+ --+ -- > 0 <= off+ --+ -- > unOffBytes off <= unCount (byteCountMem memRead - byteCountType @e)+ --+ -> e+ indexOffMem mr off = indexByteOffMem mr (toByteOff off)+ {-# INLINE indexOffMem #-}++ -- | Read an element with an offset in number of bytes. Bounds are not checked.+ --+ -- [Unsafe] When precondition for @off@ argument is violated the result is either+ -- unpredictable output or failure with a segfault.+ --+ -- @since 0.1.0+ indexByteOffMem :: Prim e+ => mr -- ^ /memRead/ - Memory to read an element from+ -> Off Word8+ -- ^ /off/ - Offset in number of elements from the beginning of @memRead@+ --+ -- /__Preconditions:__/+ --+ -- > 0 <= unOff off+ --+ -- > unOff off <= unCount (byteCountMem memRead - byteCountType @e)+ --+ -> e++ -- | Copy contiguous chunk of memory from the read only memory into the target mutable+ -- `MBytes`. Source and target /must not/ refer to the same memory region, otherwise+ -- that would imply that the source is not immutable which would be a violation of some+ -- other invariant elsewhere in the code.+ --+ -- [Unsafe] When a precondition for either of the offsets @memSourceOff@, @memTargetOff@+ -- or the element count @memCount@ is violated the result is either unpredictable output or+ -- failure with a segfault.+ --+ -- @since 0.1.0+ copyByteOffToMBytesMem ::+ (MonadPrim s m, Prim e)+ => mr -- ^ /memSourceRead/ - Source from where to copy+ -> Off Word8+ -- ^ /memSourceOff/ - Offset into source memory in number of bytes+ --+ -- /__Preconditions:__/+ --+ -- > 0 <= memSourceOff+ --+ -- > unOff memSourceOff <= unCount (byteCountMem memSourceRead - byteCountType @e)+ -> MBytes p s -- ^ /memTargetWrite/ - Target mutable memory+ -> Off Word8+ -- ^ /memTargetOff/ - Offset into target memory in number of bytes+ --+ -- /__Preconditions:__/+ --+ -- > 0 <= memTargetOff+ --+ -- > unOff memTargetOff <= unCount (byteCountMem memTargetWrite - byteCountType @e)+ -> Count e+ -- ^ /memCount/ - Number of elements of type @e@ to copy+ --+ -- /__Preconditions:__/+ --+ -- > 0 <= memCount+ --+ -- > unCountBytes memCount + unOff memSourceOff <= unCount (byteCountMem memSourceRead - byteCountType @e)+ --+ -- > unCountBytes memCount + unOff memTargetOff <= unCount (byteCountMem memTargetRead - byteCountType @e)+ -> m ()++ -- | Copy contiguous chunk of memory from the read only memory into the target mutable+ -- `Ptr`. Source and target /must not/ refer to the same memory region, otherwise that+ -- would imply that the source is not immutable which would be a violation of some other+ -- invariant elsewhere in the code.+ --+ -- [Unsafe] When any precondition for one of the offsets @memSourceOff@, @memTargetOff@+ -- or the element count @memCount@ is violated a call to this function can result in:+ -- copy of data that doesn't belong to @memSourceRead@, heap corruption or failure with+ -- a segfault.+ --+ --+ -- @since 0.1.0+ copyByteOffToPtrMem ::+ (MonadPrim s m, Prim e)+ => mr -- ^ /memSourceRead/ - Source from where to copy+ -> Off Word8+ -- ^ /memSourceOff/ - Offset into source memory in number of bytes+ --+ -- /__Preconditions:__/+ --+ -- > 0 <= memSourceOff+ --+ -- > unOff memSourceOff <= unCount (byteCountMem memSourceRead - byteCountType @e)+ -> Ptr e+ -- ^ /memTargetWrite/ - Pointer to the target mutable memory+ --+ -- /__Preconditions:__/+ --+ -- Once the pointer is advanced by @memTargetOff@ the next @unCountBytes memCount@ bytes must+ -- still belong to the same region of memory @memTargetWrite@+ -> Off Word8+ -- ^ /memTargetOff/ - Number of bytes to advance the pointer @memTargetWrite@ forward+ --+ -- /__Precondition:__/+ --+ -- Once the pointer is advanced by @memTargetOff@ it must still refer to the same+ -- memory region @memTargetWrite@+ -> Count e+ -- ^ /memCount/ - Number of elements of type @e@ to copy+ --+ -- /__Preconditions:__/+ --+ -- > 0 <= memCount+ --+ -- > unCountBytes memCount + unOff memSourceOff <= unCount (byteCountMem memSourceRead - byteCountType @e)+ -> m ()++ -- | Same as `compareByteOffMem`, but compare the read-only+ -- memory region to a region addressed by a `Ptr` inside of a `MonadPrim`.+ --+ -- [Unsafe] When any precondition for either of the offsets @memOff1@, @memOff2@, the+ -- pointer @memRead2@ or the element count @memCount@ is violated the result is either+ -- unpredictable output or failure with a segfault.+ --+ -- @since 0.1.0+ compareByteOffToPtrMem ::+ (MonadPrim s m, Prim e)+ => mr -- ^ /memRead1/ - First memory region+ -> Off Word8+ -- ^ /memOff1/ - Offset for @memRead1@ in number of bytes+ --+ -- /__Preconditions:__/+ --+ -- > 0 <= memOff1+ --+ -- > unOff memOff1 <= unCount (byteCountMem memRead1 - byteCountType @e)+ -> Ptr e+ -- ^ /memRead2/- Second memory region that can be accessed by a pointer+ --+ -- /__Preconditions__/+ --+ -- Once the pointer is advanced by @memOff2@ the next @unCountBytes memCount@ bytes must+ -- still belong to the same region of memory @memRead2@+ -> Off Word8+ -- ^ /memOff2/ - Number of bytes to advance the pointer @memRead2@ forward+ --+ -- /__Precondition:__/+ --+ -- Once the pointer is advanced by @memOff2@ it must still refer to the same memory+ -- region @memRead2@+ -> Count e -- ^ /memCount/ - Number of elements of type @e@ to compare as binary+ -- ^ /memCount/ - Number of elements of type @e@ to compare as binary+ --+ -- /__Preconditions:__/+ --+ -- > 0 <= memCount+ --+ -- > unCountBytes memCount + unOff memOff1 <= unCount (byteCountMem memRead1 - byteCountType @e)+ -> m Ordering++ -- | Same as `compareByteOffMem`, but compare the read-only memory region to `Bytes`.+ --+ -- [Unsafe] When any precondition for either of the offsets @memOff1@, @memOff2@ or the+ -- element count @memCount@ is violated the result is either unpredictable output or+ -- failure with a segfault.+ --+ -- @since 0.1.0+ compareByteOffToBytesMem ::+ Prim e+ => mr -- ^ /memRead1/ - First memory region+ -> Off Word8+ -- ^ /memOff1/ - Offset for @memRead1@ in number of bytes+ --+ -- /__Preconditions:__/+ --+ -- > 0 <= memOff1+ --+ -- > unOff memOff1 <= unCount (byteCountMem memRead1 - byteCountType @e)+ -> Bytes p -- ^ /memRead2/- Second memory region that is backed by `Bytes`+ -> Off Word8+ -- ^ /memOff2/ - Offset for @memRead2@ in number of bytes+ --+ -- /__Preconditions:__/+ --+ -- > 0 <= memOff2+ --+ -- > unOff memOff2 <= unCount (byteCountMem memRead2 - byteCountType @e)+ -> Count e+ -- ^ /memCount/ - Number of elements of type @e@ to compare as binary+ --+ -- /__Preconditions:__/+ --+ -- > 0 <= memCount+ --+ -- > unCountBytes memCount + unOff memOff1 <= unCount (byteCountMem memRead1 - byteCountType @e)+ --+ -- > unCountBytes memCount + unOff memOff2 <= unCount (byteCountMem memRead2 - byteCountType @e)+ -> Ordering++ -- | Compare two read-only regions of memory byte-by-byte. The very first mismatched+ -- byte will cause this function to produce `LT` if the byte in @memRead1@ is smaller+ -- than the one in @memRead2@ and `GT` if it is bigger. It is not a requirement to+ -- short-circuit on the first mismatch, but it is a good optimization to have for+ -- non-sensitive data. Memory regions that store security critical data may choose to+ -- implement this function to work in constant time.+ --+ -- This function is usually implemented by either one of `compareByteOffToPtrMem` or+ -- `compareByteOffToBytesMem`, depending on the nature of @mr@ type. However it differs+ -- from the aforementioned functions with a fact that it is pure non-monadic+ -- computation.+ --+ -- [Unsafe] When any precondition for either of the offsets @memOff1@, @memOff2@ or the+ -- element count @memCount@ is violated the result is either unpredictable output or+ -- failure with a segfault.+ --+ -- @since 0.1.0+ compareByteOffMem ::+ (MemRead mr', Prim e)+ => mr' -- ^ /memRead1/ - First memory region+ -> Off Word8+ -- ^ /memOff1/ - Offset for @memRead1@ in number of bytes+ --+ -- /__Preconditions:__/+ --+ -- > 0 <= memOff1+ --+ -- > unOff memOff1 <= unCount (byteCountMem memRead1 - byteCountType @e)+ -> mr -- ^ /memRead2/ - Second memory region+ -> Off Word8+ -- ^ /memOff2/ - Offset for @memRead2@ in number of bytes+ --+ -- /__Preconditions:__/+ --+ -- > 0 <= memOff2+ --+ -- > unOff memOff2 <= unCount (byteCountMem memRead2 - byteCountType @e)+ -> Count e+ -- ^ /memCount/ - Number of elements of type @e@ to compare as binary+ --+ -- /__Preconditions:__/+ --+ -- > 0 <= memCount+ --+ -- > unCountBytes memCount + unOff memOff1 <= unCount (byteCountMem memRead1 - byteCountType @e)+ --+ -- > unCountBytes memCount + unOff memOff2 <= unCount (byteCountMem memRead2 - byteCountType @e)+ -> Ordering++-- | Type class that can be implemented for a mutable data type that provides direct read+-- and write access to memory+class MemWrite mw where+ -- | Read an element with an offset in number of elements, rather than bytes as it is+ -- the case with `readByteOffMem`.+ --+ -- [Unsafe] Bounds are not checked. When precondition for @off@ argument is violated the+ -- result is either unpredictable output or failure with a segfault.+ --+ -- @since 0.1.0+ readOffMem :: (MonadPrim s m, Prim e)+ => mw s -- ^ /memRead/ - Memory region to read an element from+ -> Off e+ -- ^ /off/ - Offset in number of elements from the beginning of @memRead@+ --+ -- /__Preconditions:__/+ --+ -- > 0 <= off+ --+ -- With offset applied it should still refer to the same memory region. For types that+ -- also implement `MemAlloc` this can be described as:+ --+ -- > count <- getByteCountMem memRead+ -- > unOff (toByteOff off) <= unCount (count - byteCountType @e)+ --+ -> m e+ readOffMem mw off = readByteOffMem mw (toByteOff off)+ {-# INLINE readOffMem #-}++ -- | Read an element with an offset in number of bytes.+ --+ -- [Unsafe] Bounds are not checked. When precondition for @off@ argument is violated the+ -- result is either unpredictable output or failure with a segfault.+ --+ -- @since 0.1.0+ readByteOffMem :: (MonadPrim s m, Prim e)+ => mw s -- ^ /memRead/ - Memory region to read an element from+ -> Off Word8+ -- ^ /off/ - Offset in number of elements from the beginning of @memRead@+ --+ -- /__Preconditions:__/+ --+ -- > 0 <= off+ --+ -- With offset applied it should still refer to the same memory region. For types that+ -- also implement `MemAlloc` this can be described as:+ --+ -- > count <- getByteCountMem memRead+ -- > unOff (toByteOff off) <= unCount (count - byteCountType @e)+ --+ -> m e++ -- | Write an element with an offset in number of elements, rather than bytes as it is+ -- the case with `writeByteOffMem`.+ --+ -- [Unsafe] Bounds are not checked. When precondition for @off@ argument is violated the+ -- outcome is either heap corruption or failure with a segfault.+ --+ -- @since 0.1.0+ writeOffMem :: (MonadPrim s m, Prim e)+ => mw s -- ^ /memWrite/ - Memory region to write an element into+ -> Off e+ -- ^ /off/ - Offset in number of elements from the beginning of @memWrite@+ --+ -- /__Preconditions:__/+ --+ -- > 0 <= off+ --+ -- With offset applied it should still refer to the same memory region. For types that+ -- also implement `MemAlloc` this can be described as:+ --+ -- > count <- getByteCountMem memWrite+ -- > unOff (toByteOff off) <= unCount (count - byteCountType @e)+ --+ -> e -- ^ /elt/ - Element to write+ -> m ()+ writeOffMem mw off = writeByteOffMem mw (toByteOff off)+ {-# INLINE writeOffMem #-}++ -- | Write an element with an offset in number of bytes.+ --+ -- [Unsafe] Bounds are not checked. When precondition for @off@ argument is violated the+ -- outcome is either heap corruption or failure with a segfault.+ --+ -- @since 0.1.0+ writeByteOffMem :: (MonadPrim s m, Prim e)+ => mw s -- ^ /memWrite/ - Memory region to write an element into+ -> Off Word8+ -- ^ /off/ - Offset in number of elements from the beginning of @memWrite@+ --+ -- /__Preconditions:__/+ --+ -- > 0 <= off+ --+ -- With offset applied it should still refer to the same memory region. For types that+ -- also implement `MemAlloc` this can be described as:+ --+ -- > count <- getByteCountMem memWrite+ -- > unOff (toByteOff off) <= unCount (count - byteCountType @e)+ --+ -> e -> m ()++ -- | Copy contiguous chunk of memory from the source mutable memory into the target+ -- mutable `MBytes`. Source and target /may/ refer to overlapping memory regions.+ --+ -- [Unsafe] When any precondition for one of the offsets @memSourceOff@, @memTargetOff@+ -- or the element count @memCount@ is violated a call to this function can result in:+ -- copy of data that doesn't belong to @memSource@, heap corruption or failure with+ -- a segfault.+ --+ -- @since 0.1.0+ moveByteOffToMBytesMem ::+ (MonadPrim s m, Prim e)+ => mw s -- ^ /memSource/ - Source memory from where to copy+ -> Off Word8+ -- ^ /memSourceOff/ - Offset in number of bytes into source memory+ --+ -- /__Preconditions:__/+ --+ -- > 0 <= memSourceOff+ --+ -- With offset applied it should still refer to the same memory region. For types that+ -- also implement `MemAlloc` this can be described as:+ --+ -- > sourceByteCount <- getByteCountMem memSource+ -- > unOff (toByteOff memSourceOff) <= unCount (sourceByteCount - byteCountType @e)+ -> MBytes p s -- ^ /memTarget/ - Target memory into where to copy+ -> Off Word8+ -- ^ /memTargetOff/ - Offset in number of bytes into target memory where writing will start+ --+ -- /__Preconditions:__/+ --+ -- > 0 <= memTargetOff+ --+ -- With offset applied it should still refer to the same memory region. For types that+ -- also implement `MemAlloc` this can be described as:+ --+ -- > targetByteCount <- getByteCountMem memTarget+ -- > unOffBytes memTargetOff <= unCount (targetByteCount - byteCountType @e)+ -> Count e+ -- ^ /memCount/ - Number of elements of type @e@ to copy+ --+ -- /__Preconditions:__/+ --+ -- > 0 <= memCount+ --+ -- Both source and target memory regions must have enough memory to perform a copy+ -- of @memCount@ elements starting at their respective offsets. For types that also+ -- implement `MemAlloc` this can be described as:+ --+ -- > sourceByteCount <- getByteCountMem memSource+ -- > unOff memSourceOff + unCountBytes memCount <= unCount (sourceByteCount - byteCountType @e)+ --+ -- > targetByteCount <- getByteCountMem memTarget+ -- > unOff memTargetOff + unCountBytes memCount <= unCount (targetByteCount - byteCountType @e)+ -> m ()++ -- | Copy contiguous chunk of memory from the source mutable memory into the target+ -- `Ptr`. Source and target /may/ refer to overlapping memory regions.+ --+ -- [Unsafe] When any precondition for one of the offsets @memSourceOff@ or+ -- @memTargetOff@, a target pointer @memTarget@ or the element count @memCount@ is+ -- violated a call to this function can result in: copy of data that doesn't belong to+ -- @memSource@, heap corruption or failure with a segfault.+ --+ -- @since 0.1.0+ moveByteOffToPtrMem ::+ (MonadPrim s m, Prim e)+ => mw s -- ^ /memSource/ - Source memory from where to copy+ -> Off Word8+ -- ^ /memSourceOff/ - Offset in number of bytes into source memory+ --+ -- /__Preconditions:__/+ --+ -- > 0 <= memSourceOff+ --+ -- With offset applied it should still refer to the same memory region. For types that+ -- also implement `MemAlloc` this can be described as:+ --+ -- > sourceByteCount <- getByteCountMem memSource+ -- > unOff (toByteOff memSourceOff) <= unCount (sourceByteCount - byteCountType @e)+ -> Ptr e+ -- ^ /memTarget/ - Target memory into where to copy+ --+ -- /__Precondition:__/+ --+ -- Once the pointer is advanced by @memTargetOff@ the next @unCountBytes memCount@ bytes must+ -- still belong to the same region of memory @memTargetWrite@+ -> Off Word8+ -- ^ /memTargetOff/ - Offset in number of bytes into target memory where writing will start+ --+ -- /__Preconditions:__/+ --+ -- > 0 <= memTargetOff+ --+ -- Once the pointer is advanced by @memTargetOff@ it must still refer to the same+ -- memory region @memTarget@+ -> Count e+ -- ^ /memCount/ - Number of elements of type @e@ to copy+ --+ -- /__Preconditions:__/+ --+ -- > 0 <= memCount+ --+ -- Both source and target memory regions must have enough memory to perform a copy+ -- of @memCount@ elements starting at their respective offsets. For /memSource/ that also+ -- implements `MemAlloc` this can be described as:+ --+ -- > sourceByteCount <- getByteCountMem memSource+ -- > unOff memSourceOff + unCountBytes memCount <= unCount (sourceByteCount - byteCountType @e)+ -> m ()++ -- | Copy contiguous chunk of memory from the read only memory region into the target+ -- mutable memory region. Source and target /must not/ refer to the same memory region,+ -- otherwise that would imply that the source is not immutable which would be a+ -- violation of some other invariant elsewhere in the code.+ --+ -- [Unsafe] When any precondition for one of the offsets @memSourceOff@, @memTargetOff@+ -- or the element count @memCount@ is violated a call to this function can result in:+ -- copy of data that doesn't belong to @memSourceRead@, heap corruption or failure with+ -- a segfault.+ --+ -- @since 0.1.0+ copyByteOffMem :: (MonadPrim s m, MemRead mr, Prim e)+ => mr -- ^ /memSourceRead/ - Read-only source memory region from where to copy+ -> Off Word8+ -- ^ /memSourceOff/ - Offset into source memory in number of bytes+ --+ -- /__Preconditions:__/+ --+ -- > 0 <= memSourceOff+ --+ -- > unOff memSourceOff <= unCount (byteCountMem memSourceRead - byteCountType @e)+ -> mw s -- ^ /memTargetWrite/ - Target mutable memory+ -> Off Word8+ -- ^ /memTargetOff/ - Offset into target memory in number of bytes+ --+ -- /__Preconditions:__/+ --+ -- > 0 <= memTargetOff+ --+ -- With offset applied it should still refer to the same memory region. For types that+ -- also implement `MemAlloc` this can be described as:+ --+ -- > targetByteCount <- getByteCountMem memTargetWrite+ -- > unOffBytes memTargetOff <= unCount (targetByteCount - byteCountType @e)+ -> Count e+ -- ^ /memCount/ - Number of elements of type @e@ to copy+ --+ -- /__Preconditions:__/+ --+ -- > 0 <= memCount+ --+ -- Both source and target memory regions must have enough memory to perform a copy+ -- of @memCount@ elements starting at their respective offsets. For @memSourceRead@:+ --+ -- > unOff memSourceOff + unCountBytes memCount <= unCount (byteCountMem memSourceRead - byteCountType @e)+ --+ -- and for @memTargetWrite@ that also implements `MemAlloc` this can be described as:+ --+ -- > targetByteCount <- getByteCountMem memTargetWrite+ -- > unOff memTargetOff + unCountBytes memCount <= unCount (targetByteCount - byteCountType @e)+ -> m ()++ -- | Copy contiguous chunk of memory from a mutable memory region into the target+ -- mutable memory region. Source and target /may/ refer to the same memory region.+ --+ -- [Unsafe] When any precondition for one of the offsets @memSourceOff@, @memTargetOff@+ -- or the element count @memCount@ is violated a call to this function can result in:+ -- copy of data that doesn't belong to @memSourceRead@, heap corruption or failure with+ -- a segfault.+ --+ -- @since 0.1.0+ moveByteOffMem :: (MonadPrim s m, MemWrite mw', Prim e)+ => mw' s -- ^ /memSource/ - Source memory from where to copy+ -> Off Word8+ -- ^ /memSourceOff/ - Offset in number of bytes into source memory+ --+ -- /__Preconditions:__/+ --+ -- > 0 <= memSourceOff+ --+ -- With offset applied it should still refer to the same memory region. For types that+ -- also implement `MemAlloc` this can be described as:+ --+ -- > sourceByteCount <- getByteCountMem memSource+ -- > unOffBytes memSourceOff <= unCount (sourceByteCount - byteCountType @e)+ -> mw s -- ^ /memTarget/ - Target memory into where to copy+ -> Off Word8+ -- ^ /memTargetOff/ - Offset into target memory in number of bytes+ --+ -- /__Preconditions:__/+ --+ -- > 0 <= memTargetOff+ --+ -- With offset applied it should still refer to the same memory region. For types that+ -- also implement `MemAlloc` this can be described as:+ --+ -- > targetByteCount <- getByteCountMem memTarget+ -- > unOffBytes (toByteOff memTargetOff) <= unCount (targetByteCount - byteCountType @e)+ -> Count e+ -- ^ /memCount/ - Number of elements of type @e@ to copy+ --+ -- /__Preconditions:__/+ --+ -- > 0 <= memCount+ --+ -- Both source and target memory regions must have enough memory to perform a copy+ -- of @memCount@ elements starting at their respective offsets. For types that also+ -- implement `MemAlloc` this can be described as:+ --+ -- > sourceByteCount <- getByteCountMem memSource+ -- > unOff memSourceOff + unCountBytes memCount <= unCount (sourceByteCount - byteCountType @e)+ --+ -- > targetByteCount <- getByteCountMem memTarget+ -- > unOff memTargetOff + unCountBytes memCount <= unCount (targetByteCount - byteCountType @e)+ -> m ()++ -- TODO: Potential feature for the future implementation. Will require extra function in `Prim`.+ --setByteOffMem :: (MonadPrim s m, Prim e) => w s -> Off Word8 -> Count e -> e -> m ()++ -- | Write the same value @memCount@ times into each cell of @memTarget@ starting at an+ -- offset @memTargetOff@.+ --+ -- [Unsafe] Bounds are not checked. When precondition for @memTargetOff@ argument is+ -- violated the outcome is either heap corruption or failure with a segfault.+ --+ -- @since 0.1.0+ setMem+ :: (MonadPrim s m, Prim e)+ => mw s -- ^ /memTarget/ - Target memory into where to write the element+ -> Off e+ -- ^ /memTargetOff/ - Offset into target memory in number of elements at which element+ -- setting should start.+ --+ -- /__Preconditions:__/+ --+ -- > 0 <= memTargetOff+ --+ -- With offset applied it should still refer to the same memory region. For types that+ -- also implement `MemAlloc` this can be described as:+ --+ -- > targetByteCount <- getByteCountMem memTarget+ -- > unOffBytes memTargetOff <= unCount (targetByteCount - byteCountType @e)+ -> Count e+ -- ^ /memCount/ - Number of times the element @elt@ should be written+ --+ -- /__Preconditions:__/+ --+ -- > 0 <= memCount+ --+ -- Target memory region should have enough memory to perform a set operation of the+ -- supplied element @memCount@ number of times starting at the supplied offset. For+ -- types that also implement `MemAlloc` this can be described as:+ --+ -- > targetByteCount <- getByteCountMem memTarget+ -- > unCountBytes memCount + unOff memTargetOff <= unCount (targetByteCount - byteCountType @e)+ -> e+ -- ^ /elt/ - Element to write into memory cells. This function is strict with+ -- respect to element, which means that the even @memCount = 0@ it might be still+ -- fully evaluated.+ -> m ()++-- | Generalized memory allocation and pure/mutable state conversion.+class (MemRead (FrozenMem ma), MemWrite ma) => MemAlloc ma where+ -- | Memory region in the immutable state. Types for frozen and thawed states of+ -- memory region are in one-to-one correspondence, therefore @ma <-> FrozeMem ma@ will+ -- always uniquely identify each other, which is an extremely useful property when it+ -- comes to type inference.+ type FrozenMem ma = (fm :: Type) | fm -> ma++ -- | Extract from the mutable memory region information about how many bytes it can hold.+ --+ -- @since 0.1.0+ getByteCountMem :: MonadPrim s m => ma s -> m (Count Word8)++ -- | Allocate a mutable memory region for specified number of elements. Memory is not+ -- reset and will likely hold some garbage data, therefore prefer to use `allocZeroMem`,+ -- unless it is guaranteed that all of allocated memory will be overwritten.+ --+ -- [Unsafe] When precondition for @memCount@ argument is violated the outcome is+ -- upredictable. One possible outcome is termination with+ -- `Control.Exception.HeapOverflow` async exception. In a pure setting, such as when+ -- executed within `runST`, if memory is not fully overwritten it can result in+ -- violation of referential transparency, because content of newly allocated+ -- region is non-determinstic.+ --+ -- @since 0.1.0+ allocMem :: (Prim e, MonadPrim s m)+ => Count e+ -- ^ /memCount/ - Number of elements to allocate.+ --+ -- /__Preconditions:__/+ --+ -- > 0 <= memCount+ --+ -- Possibility of overflow:+ --+ -- > unCount memCount <= fromByteCount @e (Count maxBound)+ --+ -- When converted to bytes the value should be less then available physical memory+ -> m (ma s)++ -- | Convert the state of an immutable memory region to the mutable one. This is a no+ -- copy operation, as such it is fast, but dangerous. See `thawCopyMem` for a safe alternative.+ --+ -- [Unsafe] It makes it possible to break referential transparency, because any+ -- subsequent destructive operation to the mutable region of memory will also be+ -- reflected in the frozen immutable type as well.+ --+ -- @since 0.1.0+ thawMem :: MonadPrim s m => FrozenMem ma -> m (ma s)++ -- | Convert the state of a mutable memory region to the immutable one. This is a no+ -- copy operation, as such it is fast, but dangerous. See `freezeCopyMem` for a safe alternative.+ --+ -- [Unsafe] It makes it possible to break referential transparency, because any+ -- subsequent destructive operation to the mutable region of memory will also be+ -- reflected in the frozen immutable type as well.+ --+ -- @since 0.1.0+ freezeMem :: MonadPrim s m => ma s -> m (FrozenMem ma)++ -- | Either grow or shrink currently allocated mutable region of memory. For some+ -- implementations it might be possible to change the size of the allocated region+ -- in-place, i.e. without copy. However in all implementations there is a good chance+ -- that the memory region has to be allocated anew, in which case all of the contents+ -- up to the minimum of new and old sizes will get copied over. After the resize+ -- operation is complete the supplied @memSource@ region must not be used+ -- anymore. Moreover, no reference to the old one should be kept in order to allow+ -- garbage collection of the original in case a new one had to be allocated.+ --+ -- [Unsafe] Undefined behavior when @memSource@ is used afterwards. The same unsafety+ -- notice from `allocMem` with regards to @memCount@ is applcable here as well.+ --+ -- @since 0.1.0+ resizeMem :: (MonadPrim s m, Prim e)+ => ma s+ -- ^ /memSource/ - Source memory region to resize+ -> Count e+ -- ^ /memCount/ - Number of elements for the reallocated memory region+ --+ -- /__Preconditions:__/+ --+ -- > 0 <= memCount+ --+ -- Should be less then available physical memory+ -> m (ma s)+ resizeMem = defaultResizeMem+ {-# INLINE resizeMem #-}+++instance MemRead ByteString where+ byteCountMem = Count . BS.length+ {-# INLINE byteCountMem #-}+ indexOffMem bs i = unsafeInlineIO $ withPtrAccess bs (`readOffPtr` i)+ {-# INLINE indexOffMem #-}+ indexByteOffMem bs i = unsafeInlineIO $ withPtrAccess bs (`readByteOffPtr` i)+ {-# INLINE indexByteOffMem #-}+ copyByteOffToMBytesMem bs srcOff mb dstOff c =+ withPtrAccess bs $ \srcPtr -> copyByteOffPtrToMBytes srcPtr srcOff mb dstOff c+ {-# INLINE copyByteOffToMBytesMem #-}+ copyByteOffToPtrMem bs srcOff dstPtr dstOff c =+ withPtrAccess bs $ \srcPtr -> copyByteOffPtrToPtr srcPtr srcOff dstPtr dstOff c+ {-# INLINE copyByteOffToPtrMem #-}+ compareByteOffToPtrMem bs off1 ptr2 off2 c =+ withPtrAccess bs $ \ptr1 -> pure $! compareByteOffPtrToPtr ptr1 off1 ptr2 off2 c+ {-# INLINE compareByteOffToPtrMem #-}+ compareByteOffToBytesMem bs off1 bytes off2 c =+ unsafeInlineIO $ withPtrAccess bs $ \ptr1 ->+ pure $! compareByteOffPtrToBytes ptr1 off1 bytes off2 c+ {-# INLINE compareByteOffToBytesMem #-}+ compareByteOffMem mem1 off1 bs off2 c =+ unsafeInlineIO $ withPtrAccess bs $ \ptr2 -> compareByteOffToPtrMem mem1 off1 ptr2 off2 c+ {-# INLINE compareByteOffMem #-}+++instance MemAlloc MByteString where+ type FrozenMem MByteString = ByteString+ getByteCountMem (MByteString bs) = pure $! Count (BS.length bs)+ {-# INLINE getByteCountMem #-}+ allocMem c = do+ let cb = toByteCount c+ fp <- mallocByteCountPlainForeignPtr cb+ pure $ MByteString (PS fp 0 (coerce cb))+ {-# INLINE allocMem #-}+ thawMem bs = pure $ MByteString bs+ {-# INLINE thawMem #-}+ freezeMem (MByteString bs) = pure bs+ {-# INLINE freezeMem #-}+ resizeMem bsm@(MByteString (PS fp o n)) newc+ | newn > n = defaultResizeMem bsm newc+ | otherwise = pure $ MByteString (PS fp o newn)+ where -- constant time slice if we need to reduce the size+ Count newn = toByteCount newc+ {-# INLINE resizeMem #-}++instance MemWrite MByteString where+ readOffMem (MByteString mbs) i = withPtrAccess mbs (`readOffPtr` i)+ {-# INLINE readOffMem #-}+ readByteOffMem (MByteString mbs) i = withPtrAccess mbs (`readByteOffPtr` i)+ {-# INLINE readByteOffMem #-}+ writeOffMem (MByteString mbs) i a = withPtrAccess mbs $ \ptr -> writeOffPtr ptr i a+ {-# INLINE writeOffMem #-}+ writeByteOffMem (MByteString mbs) i a = withPtrAccess mbs $ \ptr -> writeByteOffPtr ptr i a+ {-# INLINE writeByteOffMem #-}+ moveByteOffToPtrMem (MByteString fsrc) srcOff dstPtr dstOff c =+ withPtrAccess fsrc $ \srcPtr -> moveByteOffPtrToPtr srcPtr srcOff dstPtr dstOff c+ {-# INLINE moveByteOffToPtrMem #-}+ moveByteOffToMBytesMem (MByteString fsrc) srcOff dst dstOff c =+ withPtrAccess fsrc $ \srcPtr -> moveByteOffPtrToMBytes srcPtr srcOff dst dstOff c+ {-# INLINE moveByteOffToMBytesMem #-}+ copyByteOffMem src srcOff (MByteString fdst) dstOff c =+ withPtrAccess fdst $ \dstPtr -> copyByteOffToPtrMem src srcOff dstPtr dstOff c+ {-# INLINE copyByteOffMem #-}+ moveByteOffMem src srcOff (MByteString fdst) dstOff c =+ withPtrAccess fdst $ \dstPtr -> moveByteOffToPtrMem src srcOff dstPtr dstOff c+ {-# INLINE moveByteOffMem #-}+ setMem (MByteString mbs) off c a = withPtrAccess mbs $ \ptr -> setOffPtr ptr off c a+ {-# INLINE setMem #-}++instance MemRead T.Array where+ byteCountMem = byteCountMem . T.toBytesArray+ {-# INLINE byteCountMem #-}+ indexOffMem a = indexOffMem (T.toBytesArray a)+ {-# INLINE indexOffMem #-}+ indexByteOffMem a = indexByteOffMem (T.toBytesArray a)+ {-# INLINE indexByteOffMem #-}+ copyByteOffToMBytesMem a = copyByteOffToMBytesMem (T.toBytesArray a)+ {-# INLINE copyByteOffToMBytesMem #-}+ copyByteOffToPtrMem a = copyByteOffToPtrMem (T.toBytesArray a)+ {-# INLINE copyByteOffToPtrMem #-}+ compareByteOffToPtrMem a = compareByteOffToPtrMem (T.toBytesArray a)+ {-# INLINE compareByteOffToPtrMem #-}+ compareByteOffToBytesMem a = compareByteOffToBytesMem (T.toBytesArray a)+ {-# INLINE compareByteOffToBytesMem #-}+ compareByteOffMem mem off1 a = compareByteOffMem mem off1 (T.toBytesArray a)+ {-# INLINE compareByteOffMem #-}++instance MemAlloc T.MArray where+ type FrozenMem T.MArray = T.Array+ getByteCountMem = getByteCountMBytes . T.toMBytesMArray+ {-# INLINE getByteCountMem #-}+ allocMem = fmap T.fromMBytesMArray . allocUnpinnedMBytes+ {-# INLINE allocMem #-}+ thawMem = fmap T.fromMBytesMArray . thawBytes . T.toBytesArray+ {-# INLINE thawMem #-}+ freezeMem = fmap T.fromBytesArray . freezeMBytes . T.toMBytesMArray+ {-# INLINE freezeMem #-}+ resizeMem m = fmap T.fromMBytesMArray . reallocMBytes (T.toMBytesMArray m)+ {-# INLINE resizeMem #-}++instance MemWrite T.MArray where+ readOffMem m = readOffMBytes (T.toMBytesMArray m)+ {-# INLINE readOffMem #-}+ readByteOffMem m = readByteOffMBytes (T.toMBytesMArray m)+ {-# INLINE readByteOffMem #-}+ writeOffMem m = writeOffMBytes (T.toMBytesMArray m)+ {-# INLINE writeOffMem #-}+ writeByteOffMem m = writeByteOffMBytes (T.toMBytesMArray m)+ {-# INLINE writeByteOffMem #-}+ moveByteOffToPtrMem m = moveByteOffMBytesToPtr (T.toMBytesMArray m)+ {-# INLINE moveByteOffToPtrMem #-}+ moveByteOffToMBytesMem m = moveByteOffMBytesToMBytes (T.toMBytesMArray m)+ {-# INLINE moveByteOffToMBytesMem #-}+ moveByteOffMem src srcOff m = moveByteOffToMBytesMem src srcOff (T.toMBytesMArray m)+ {-# INLINE moveByteOffMem #-}+ copyByteOffMem src srcOff m = copyByteOffToMBytesMem src srcOff (T.toMBytesMArray m)+ {-# INLINE copyByteOffMem #-}+ setMem m = setMBytes (T.toMBytesMArray m)+ {-# INLINE setMem #-}++instance MemRead T.Text where+ byteCountMem (T.Text _ _ n) = toByteCount (Count n :: Count Word16)+ {-# INLINE byteCountMem #-}+ indexByteOffMem (T.Text a o _) i = indexByteOffMem a (toByteOff (Off o :: Off Word16) + i)+ {-# INLINE indexByteOffMem #-}+ copyByteOffToMBytesMem (T.Text a o _) i =+ copyByteOffToMBytesMem a (toByteOff (Off o :: Off Word16) + i)+ {-# INLINE copyByteOffToMBytesMem #-}+ copyByteOffToPtrMem (T.Text a o _) i =+ copyByteOffToPtrMem a (toByteOff (Off o :: Off Word16) + i)+ {-# INLINE copyByteOffToPtrMem #-}+ compareByteOffToPtrMem (T.Text a o _) off =+ compareByteOffToPtrMem a (toByteOff (Off o :: Off Word16) + off)+ {-# INLINE compareByteOffToPtrMem #-}+ compareByteOffToBytesMem (T.Text a o _) off =+ compareByteOffToBytesMem a (toByteOff (Off o :: Off Word16) + off)+ {-# INLINE compareByteOffToBytesMem #-}+ compareByteOffMem mem off1 (T.Text a o _) off2 =+ compareByteOffMem mem off1 a (toByteOff (Off o :: Off Word16) + off2)+ {-# INLINE compareByteOffMem #-}+++instance MemRead ShortByteString where+ byteCountMem = byteCountMem . fromShortByteStringBytes+ {-# INLINE byteCountMem #-}+ indexOffMem sbs = indexOffMem (fromShortByteStringBytes sbs)+ {-# INLINE indexOffMem #-}+ indexByteOffMem sbs = indexByteOffMem (fromShortByteStringBytes sbs)+ {-# INLINE indexByteOffMem #-}+ copyByteOffToMBytesMem sbs = copyByteOffToMBytesMem (fromShortByteStringBytes sbs)+ {-# INLINE copyByteOffToMBytesMem #-}+ copyByteOffToPtrMem sbs = copyByteOffToPtrMem (fromShortByteStringBytes sbs)+ {-# INLINE copyByteOffToPtrMem #-}+ compareByteOffToPtrMem sbs = compareByteOffToPtrMem (fromShortByteStringBytes sbs)+ {-# INLINE compareByteOffToPtrMem #-}+ compareByteOffToBytesMem sbs = compareByteOffToBytesMem (fromShortByteStringBytes sbs)+ {-# INLINE compareByteOffToBytesMem #-}+ compareByteOffMem mem off1 sbs = compareByteOffMem mem off1 (fromShortByteStringBytes sbs)+ {-# INLINE compareByteOffMem #-}++-- | A wrapper that adds a phantom state token. It can be used with types that either+-- doesn't have such state token or are designed to work in `IO` and therefore restricted+-- to `RW`. Using this wrapper is very much unsafe, so make sure you know what you are+-- doing.+newtype MemState a s = MemState { unMemState :: a }++instance MemWrite (MemState (ForeignPtr a)) where+ readOffMem (MemState fptr) i = withForeignPtr fptr $ \ptr -> readOffPtr (castPtr ptr) i+ {-# INLINE readOffMem #-}+ readByteOffMem (MemState fptr) i =+ withForeignPtr fptr $ \ptr -> readByteOffPtr (castPtr ptr) i+ {-# INLINE readByteOffMem #-}+ writeOffMem (MemState fptr) i a = withForeignPtr fptr $ \ptr -> writeOffPtr (castPtr ptr) i a+ {-# INLINE writeOffMem #-}+ writeByteOffMem (MemState fptr) i a =+ withForeignPtr fptr $ \ptr -> writeByteOffPtr (castPtr ptr) i a+ {-# INLINE writeByteOffMem #-}+ moveByteOffToPtrMem (MemState fsrc) srcOff dstPtr dstOff c =+ withForeignPtr fsrc $ \srcPtr -> moveByteOffPtrToPtr (castPtr srcPtr) srcOff dstPtr dstOff c+ {-# INLINE moveByteOffToPtrMem #-}+ moveByteOffToMBytesMem (MemState fsrc) srcOff dst dstOff c =+ withForeignPtr fsrc $ \srcPtr -> moveByteOffPtrToMBytes (castPtr srcPtr) srcOff dst dstOff c+ {-# INLINE moveByteOffToMBytesMem #-}+ copyByteOffMem src srcOff (MemState fdst) dstOff c =+ withForeignPtr fdst $ \dstPtr ->+ copyByteOffToPtrMem src srcOff (castPtr dstPtr) dstOff c+ {-# INLINE copyByteOffMem #-}+ moveByteOffMem src srcOff (MemState fdst) dstOff c =+ withForeignPtr fdst $ \dstPtr ->+ moveByteOffToPtrMem src srcOff (castPtr dstPtr) dstOff c+ {-# INLINE moveByteOffMem #-}+ setMem (MemState fptr) off c a = withForeignPtr fptr $ \ptr -> setOffPtr (castPtr ptr) off c a+ {-# INLINE setMem #-}++modifyFetchOldMem ::+ (MemWrite mw, MonadPrim s m, Prim e) => mw s -> Off e -> (e -> e) -> m e+modifyFetchOldMem mem o f = modifyFetchOldMemM mem o (pure . f)+{-# INLINE modifyFetchOldMem #-}+++modifyFetchNewMem ::+ (MemWrite mw, MonadPrim s m, Prim e) => mw s -> Off e -> (e -> e) -> m e+modifyFetchNewMem mem o f = modifyFetchNewMemM mem o (pure . f)+{-# INLINE modifyFetchNewMem #-}+++modifyFetchOldMemM ::+ (MemWrite mw, MonadPrim s m, Prim e) => mw s -> Off e -> (e -> m e) -> m e+modifyFetchOldMemM mem o f = do+ a <- readOffMem mem o+ a <$ (writeOffMem mem o =<< f a)+{-# INLINE modifyFetchOldMemM #-}+++modifyFetchNewMemM ::+ (MemWrite mw, MonadPrim s m, Prim e) => mw s -> Off e -> (e -> m e) -> m e+modifyFetchNewMemM mem o f = do+ a <- readOffMem mem o+ a' <- f a+ a' <$ writeOffMem mem o a'+{-# INLINE modifyFetchNewMemM #-}+++defaultResizeMem ::+ (Prim e, MemAlloc ma, MonadPrim s m) => ma s -> Count e -> m (ma s)+defaultResizeMem mem c = do+ let newByteCount = toByteCount c+ oldByteCount <- getByteCountMem mem+ if oldByteCount == newByteCount+ then pure mem+ else do+ newMem <- allocMem newByteCount+ oldMem <- freezeMem mem+ newMem <$ copyMem oldMem 0 newMem 0 oldByteCount+{-# INLINE defaultResizeMem #-}+++-- | Place @n@ copies of supplied region of memory one after another in a newly allocated+-- contiguous chunk of memory. Similar to `stimes`, but the source memory @memRead@ does+-- not have to match the type of `FrozenMem` ma.+--+-- ====__Example__+--+-- >>> :set -XTypeApplications+-- >>> :set -XDataKinds+-- >>> import Data.Prim.Memory+-- >>> let b = fromListMem @Word8 @(MBytes 'Inc) [0xde, 0xad, 0xbe, 0xef]+-- >>> cycleMemN @(MBytes 'Inc) 2 b+-- [0xde,0xad,0xbe,0xef,0xde,0xad,0xbe,0xef]+--+-- @since 0.1.0+cycleMemN ::+ forall ma mr. (MemAlloc ma, MemRead mr)+ => Int+ -> mr+ -> FrozenMem ma+cycleMemN n r+ | n <= 0 = emptyMem+ | otherwise =+ runST $ do+ let bc@(Count chunk) = byteCountMem r+ c@(Count c8) = Count n * bc+ mem <- allocMem c+ let go i = when (i < c8) $ copyByteOffMem r 0 mem (Off i) bc >> go (i + chunk)+ go 0+ freezeMem mem+{-# INLINE cycleMemN #-}+++-- | Construct an immutable memory region that can't hold any data. Same as @`mempty` ::+-- `FrozenMem` ma@+--+-- ====__Example__+--+-- >>> :set -XTypeApplications+-- >>> :set -XDataKinds+-- >>> import Data.Prim.Memory+-- >>> toListMem (emptyMem @(MBytes 'Inc)) :: [Int]+-- []+--+-- @since 0.1.0+emptyMem ::+ forall ma. MemAlloc ma+ => FrozenMem ma+emptyMem = createMemST_ (0 :: Count Word8) (\_ -> pure ())+{-# INLINE emptyMem #-}++-- | Allocate a region of immutable memory that holds a single element.+--+-- ====__Example__+--+-- >>> :set -XTypeApplications+-- >>> :set -XDataKinds+-- >>> import Data.Prim.Memory+-- >>> toListMem (singletonMem @Word16 @(MBytes 'Inc) 0xffff) :: [Word8]+-- [255,255]+--+-- @since 0.1.0+singletonMem ::+ forall e ma. (MemAlloc ma, Prim e)+ => e -- ^ The single element that will be stored in the newly allocated region of memory+ -> FrozenMem ma+singletonMem a = createMemST_ (1 :: Count e) $ \mem -> writeOffMem mem 0 a+{-# INLINE singletonMem #-}++-- | Same as `allocMem`, but also use `setMem` to reset all of newly allocated memory to+-- zeros.+--+-- [Unsafe] When precondition for @memCount@ argument is violated the outcome is+-- upredictable. One possible outcome is termination with `Control.Exception.HeapOverflow`+-- async exception.+--+-- ====__Example__+--+-- >>> :set -XTypeApplications+-- >>> :set -XDataKinds+-- >>> import Data.Prim.Memory+-- >>> mb <- allocZeroMem @Int @(MBytes 'Inc) 10+-- >>> b <- freezeMem mb+-- >>> toListMem b :: [Int]+-- [0,0,0,0,0,0,0,0,0,0]+--+-- @since 0.1.0+allocZeroMem ::+ forall e ma m s. (MemAlloc ma, MonadPrim s m, Prim e)+ => Count e+ -- ^ /memCount/ - Number of elements to allocate.+ --+ -- /__Preconditions:__/+ --+ -- > 0 <= memCount+ --+ -- Converted to bytes should be less then available physical memory+ -> m (ma s)+allocZeroMem n = do+ m <- allocMem n+ m <$ setMem m 0 (toByteCount n) (0 :: Word8)+{-# INLINE allocZeroMem #-}+++createMemST ::+ forall e b ma. (MemAlloc ma, Prim e)+ => Count e+ -> (forall s. ma s -> ST s b)+ -> (b, FrozenMem ma)+createMemST n f = runST $ allocMem n >>= \m -> (,) <$> f m <*> freezeMem m+{-# INLINE createMemST #-}++createMemST_ :: (MemAlloc ma, Prim e)+ => Count e+ -> (forall s . ma s -> ST s b)+ -- ^ /fillAction/ -- Action that will be used to modify contents of newly allocated+ -- memory.+ --+ -- /__Required invariant:__/+ --+ -- It is important that this action overwrites all of newly allocated memory.+ -> FrozenMem ma+createMemST_ n f = runST (allocMem n >>= \m -> f m >> freezeMem m)+{-# INLINE createMemST_ #-}++createZeroMemST ::+ forall e ma b. (MemAlloc ma, Prim e)+ => Count e+ -> (forall s. ma s -> ST s b)+ -> (b, FrozenMem ma)+createZeroMemST n f = runST $ allocZeroMem n >>= \m -> (,) <$> f m <*> freezeMem m+{-# INLINE createZeroMemST #-}++-- | Same as `createMemST_`, except it ensures that the memory gets reset with zeros prior+-- to applying the @ST@ filling action @fillAction@.+--+-- [Unsafe] Same reasons as `allocZeroMem`: violation of precondition for @memCount@ may+-- result in undefined behavior or `Control.Exception.HeapOverflow` async exception.+--+-- ====__Example__+--+-- Note that this example will work correctly only on little-endian machines:+--+-- >>> :set -XTypeApplications+-- >>> import Data.Prim+-- >>> import Control.Monad+-- >>> let ibs = zip [0, 4 ..] [0x48,0x61,0x73,0x6b,0x65,0x6c,0x6c] :: [(Off Word8, Word8)]+-- >>> let c = Count (length ibs) :: Count Char+-- >>> let bc = createZeroMemST_ @_ @(MBytes 'Inc) c $ \m -> forM_ ibs $ \(i, b) -> writeByteOffMem m i b+-- >>> toListMem bc :: String+-- "Haskell"+--+-- @since 0.1.0+createZeroMemST_ ::+ forall e ma b. (MemAlloc ma, Prim e)+ => Count e+ -- ^ /memCount/ - Size of the newly allocated memory region in number of elements of+ -- type @e@+ --+ -- /__Precoditions:__/+ --+ -- Size should be non-negative, but smaller than amount of available memory. Note that the+ -- second condition simply describes overflow.+ --+ -- > 0 <= memCount+ --+ -- Possibility of overflow:+ --+ -- > unCount memCount <= fromByteCount @e (Count maxBound)+ -> (forall s. ma s -> ST s b)+ -- ^ /fillAction/ -- Action that will be used to modify contents of newly allocated+ -- memory. It is not required to overwrite the full region, since it was reset to zeros+ -- right after allocation.+ -> FrozenMem ma+createZeroMemST_ n f = runST (allocZeroMem n >>= \m -> f m >> freezeMem m)+{-# INLINE createZeroMemST_ #-}++-- | Copy all of the data from the source into a newly allocate memory region of identical+-- size.+--+-- ====__Examples__+--+-- >>> :set -XDataKinds+-- >>> import Data.Prim.Memory+-- >>> let xs = fromByteListMem @(MBytes 'Pin) [0..15] :: Bytes 'Pin+-- >>> let ys = cloneMem xs+-- >>> let report bEq pEq = print $ "Bytes equal: " ++ show bEq ++ ", their pointers equal: " ++ show pEq+-- >>> withPtrBytes xs $ \ xsPtr -> withPtrBytes ys $ \ ysPtr -> report (xs == ys) (xsPtr == ysPtr)+-- "Bytes equal: True, their pointers equal: False"+--+-- @since 0.2.0+cloneMem ::+ forall ma. MemAlloc ma+ => FrozenMem ma -- ^ /memSource/ - immutable source memory.+ -> FrozenMem ma+cloneMem fm =+ runST $ do+ let n = byteCountMem fm+ mm <- allocMem n+ copyMem fm 0 mm 0 n+ freezeMem mm+{-# INLINE cloneMem #-}++-- | Similar to `copyByteOffMem`, but supply offsets in number of elements instead of+-- bytes. Copy contiguous chunk of memory from the read only memory region into the target+-- mutable memory region. Source and target /must not/ refer to the same memory region,+-- otherwise that would imply that the source is not immutable which would be a violation+-- of some other invariant elsewhere in the code.+--+-- [Unsafe] When any precondition for one of the offsets @memSourceOff@, @memTargetOff@+-- or the element count @memCount@ is violated a call to this function can result in:+-- copy of data that doesn't belong to @memSourceRead@, heap corruption or failure with+-- a segfault.+--+-- @since 0.1.0+copyMem ::+ (MonadPrim s m, MemRead mr, MemWrite mw, Prim e)+ => mr -- ^ /memSourceRead/ - Read-only source memory region from where to copy+ -> Off e+ -- ^ /memSourceOff/ - Offset into source memory in number of elements of type @e@+ --+ -- /__Preconditions:__/+ --+ -- > 0 <= memSourceOff+ --+ -- > unOff memSourceOff < unCount (countMem memSourceRead)+ -> mw s -- ^ /memTargetWrite/ - Target mutable memory+ -> Off e+ -- ^ /memTargetOff/ - Offset into target memory in number of elements+ --+ -- /__Preconditions:__/+ --+ -- > 0 <= memTargetOff+ --+ -- With offset applied it should still refer to the same memory region. For types that+ -- also implement `MemAlloc` this can be described as:+ --+ -- > targetCount <- getCountMem memTargetWrite+ -- > unOff memTargetOff < unCount targetCount+ -> Count e+ -- ^ /memCount/ - Number of elements of type @e@ to copy+ --+ -- /__Preconditions:__/+ --+ -- > 0 <= memCount+ --+ -- Both source and target memory regions must have enough memory to perform a copy+ -- of @memCount@ elements starting at their respective offsets. For @memSourceRead@:+ --+ -- > unOff memSourceOff + unCount memCount < unCount (countMem memSourceRead)+ --+ -- and for @memTargetWrite@ that also implements `MemAlloc` this can be described as:+ --+ -- > targetCount <- getCountMem memTargetWrite+ -- > unOff memTargetOff + unCount memCount < unCount targetCount+ -> m ()+copyMem src srcOff dst dstOff = copyByteOffMem src (toByteOff srcOff) dst (toByteOff dstOff)+{-# INLINE copyMem #-}+++moveMem ::+ (MonadPrim s m, MemWrite mw1, MemWrite mw2, Prim e)+ => mw1 s -- ^ Source memory region+ -> Off e -- ^ Offset into the source in number of elements+ -> mw2 s -- ^ Destination memory region+ -> Off e -- ^ Offset into destination in number of elements+ -> Count e -- ^ Number of elements to copy over+ -> m ()+moveMem src srcOff dst dstOff = moveByteOffMem src (toByteOff srcOff) dst (toByteOff dstOff)+{-# INLINE moveMem #-}+++appendMem ::+ forall mr1 mr2 ma. (MemRead mr1, MemRead mr2, MemAlloc ma)+ => mr1+ -> mr2+ -> FrozenMem ma+appendMem r1 r2 =+ createMemST_ (n1 + n2) $ \mem -> do+ copyMem r1 0 mem 0 n1+ copyMem r2 (coerce n1) mem (coerce n1) n2+ where+ n1 = byteCountMem r1+ n2 = byteCountMem r2+{-# INLINABLE appendMem #-}++concatMem ::+ forall mr ma. (MemRead mr, MemAlloc ma)+ => [mr]+ -> FrozenMem ma+concatMem xs = do+ let c = Foldable.foldl' (\ !acc b -> acc + byteCountMem b) 0 xs+ createMemST_ c $ \mb -> do+ let load i b = do+ let cb@(Count n) = byteCountMem b :: Count Word8+ (i + Off n) <$ copyMem b 0 mb i cb+ foldM_ load 0 xs+{-# INLINABLE concatMem #-}+++thawCopyMem ::+ forall e mr ma m s. (Prim e, MemRead mr, MemAlloc ma, MonadPrim s m)+ => mr+ -> Off e+ -> Count e+ -> m (ma s)+thawCopyMem a off c = do+ mem <- allocMem c+ mem <$ copyMem a off mem 0 c+{-# INLINE thawCopyMem #-}++freezeCopyMem ::+ forall e ma m s. (Prim e, MemAlloc ma, MonadPrim s m)+ => ma s+ -> Off e+ -> Count e+ -> m (FrozenMem ma)+freezeCopyMem mem off c = freezeMem mem >>= \r -> thawCopyMem r off c >>= freezeMem+{-# INLINE freezeCopyMem #-}+++thawCloneMem ::+ forall mr ma m s. (MemRead mr, MemAlloc ma, MonadPrim s m)+ => mr+ -> m (ma s)+thawCloneMem a = thawCopyMem a 0 (byteCountMem a)+{-# INLINE thawCloneMem #-}++freezeCloneMem ::+ forall ma m s. (MemAlloc ma, MonadPrim s m)+ => ma s+ -> m (FrozenMem ma)+freezeCloneMem = freezeMem >=> thawCloneMem >=> freezeMem+{-# INLINE freezeCloneMem #-}++-- | /O(n)/ - Convert a read-only memory region into a newly allocated other type of+-- memory region+--+-- >>> import Data.ByteString (pack)+-- >>> bs = pack [0x10 .. 0x20]+-- >>> bs+-- "\DLE\DC1\DC2\DC3\DC4\NAK\SYN\ETB\CAN\EM\SUB\ESC\FS\GS\RS\US "+-- >>> convertMem bs :: Bytes 'Inc+-- [0x10,0x11,0x12,0x13,0x14,0x15,0x16,0x17,0x18,0x19,0x1a,0x1b,0x1c,0x1d,0x1e,0x1f,0x20]+--+-- @since 0.1.0+convertMem :: (MemRead mr, MemAlloc ma) => mr -> FrozenMem ma+convertMem a = runST $ thawCloneMem a >>= freezeMem+{-# INLINE convertMem #-}++-- | Figure out how many elements fits into the immutable region of memory. It is+-- possible that there is a remainder of bytes left, see `countRemMem` for getting that+-- too.+--+-- ====__Examples__+--+-- >>> b = fromListMem [0 .. 5 :: Word8] :: Bytes 'Pin+-- >>> b+-- [0x00,0x01,0x02,0x03,0x04,0x05]+-- >>> countMem b :: Count Word16+-- Count {unCount = 3}+-- >>> countMem b :: Count Word32+-- Count {unCount = 1}+--+-- @since 0.1.0+countMem ::+ forall e mr. (MemRead mr, Prim e)+ => mr+ -> Count e+countMem = fromByteCount . byteCountMem+{-# INLINE countMem #-}++-- | Compute how many elements and a byte size remainder that can fit into the region of memory.+--+-- ====__Examples__+--+-- >>> b = fromListMem [0 .. 5 :: Word8] :: Bytes 'Pin+-- >>> b+-- [0x00,0x01,0x02,0x03,0x04,0x05]+-- >>> countRemMem @Word16 b+-- (Count {unCount = 3},Count {unCount = 0})+-- >>> countRemMem @Word32 b+-- (Count {unCount = 1},Count {unCount = 2})+--+-- @since 0.1.0+countRemMem :: forall e mr. (MemRead mr, Prim e) => mr -> (Count e, Count Word8)+countRemMem = fromByteCountRem . byteCountMem+{-# INLINE countRemMem #-}++getCountMem :: forall e ma m s. (MemAlloc ma, MonadPrim s m, Prim e) => ma s -> m (Count e)+getCountMem = fmap (fromByteCount . coerce) . getByteCountMem+{-# INLINE getCountMem #-}+++getCountRemMem ::+ forall e ma m s. (MemAlloc ma, MonadPrim s m, Prim e)+ => ma s+ -> m (Count e, Count Word8)+getCountRemMem = fmap (fromByteCountRem . coerce) . getByteCountMem+{-# INLINE getCountRemMem #-}+++clone ::+ forall ma m s. (MemAlloc ma, MonadPrim s m)+ => ma s+ -> m (ma s)+clone mb = do+ n <- getByteCountMem mb+ mb' <- allocMem n+ mb' <$ moveMem mb 0 mb' 0 n+{-# INLINE clone #-}++-- | Compare two memory regions byte-by-byte. `False` is returned immediately when sizes+-- reported by `byteCountMem` do not match. Computation may be short-circuited on the+-- first mismatch, but it is `MemRead` implementation specific.+--+-- @since 0.1.0+eqMem :: (MemRead mr1, MemRead mr2) => mr1 -> mr2 -> Bool+eqMem b1 b2 = n == byteCountMem b2 && compareByteOffMem b1 0 b2 0 n == EQ+ where+ n = byteCountMem b1+{-# INLINE eqMem #-}++-- | Compare two regions of memory byte-by-byte. It will return `EQ` whenever both regions+-- are exactly the same and `LT` or `GT` as soon as the first byte is reached that is less+-- than or greater than respectfully in the first region when compared to the second+-- one. It is safe for both regions to refer to the same part of memory, since this is a+-- pure function and both regions of memory are read-only.+compareMem ::+ forall e mr1 mr2. (MemRead mr1, MemRead mr2, Prim e)+ => mr1 -- ^ First region of memory+ -> Off e -- ^ Offset in number of elements into the first region+ -> mr2 -- ^ Second region of memory+ -> Off e -- ^ Offset in number of elements into the second region+ -> Count e -- ^ Number of elements to compare+ -> Ordering+compareMem r1 off1 r2 off2 = compareByteOffMem r1 (toByteOff off1) r2 (toByteOff off2)+{-# INLINE compareMem #-}++-- =============== --+-- List conversion --+-- =============== --++-------------+-- To List --+-------------++-- | Convert an immutable memory region to a list. Whenever memory byte count is not+-- exactly divisible by the size of the element there will be some slack left unaccounted+-- for. In order to get a hold of this slack use `toListSlackMem` instead.+--+-- ====__Examples__+--+-- >>> import Data.Prim.Memory+-- >>> import Numeric (showHex)+-- >>> let b = fromByteListMem [0x48,0x61,0x73,0x6b,0x65,0x6c,0x6c] :: Bytes 'Inc+-- >>> toListMem b :: [Int8]+-- [72,97,115,107,101,108,108]+-- >>> let xs = toListMem b :: [Word32]+-- >>> xs+-- [1802723656]+-- >>> showHex (head xs) ""+-- "6b736148"+--+-- @since 0.1.0+toListMem :: forall e mr. (MemRead mr, Prim e) => mr -> [e]+toListMem ba = build (\ c n -> foldrCountMem (countMem ba) c n ba)+{-# INLINE toListMem #-}+{-# SPECIALIZE toListMem :: Prim e => Bytes p -> [e] #-}++-- | Same as `toListMem`, except when there is some slack towards the end of the memory+-- region that didn't fit into a list it will be returned as a list of bytes.+--+-- ====__Examples__+--+-- >>> import Data.Word+-- >>> :set -XDataKinds+-- >>> a = fromListMem [0 .. 10 :: Word8] :: Bytes 'Pin+-- >>> a+-- [0x00,0x01,0x02,0x03,0x04,0x05,0x06,0x07,0x08,0x09,0x0a]+-- >>> toListSlackMem a :: ([Word8], [Word8])+-- ([0,1,2,3,4,5,6,7,8,9,10],[])+-- >>> toListSlackMem a :: ([Word16], [Word8])+-- ([256,770,1284,1798,2312],[10])+-- >>> toListSlackMem a :: ([Word32], [Word8])+-- ([50462976,117835012],[8,9,10])+-- >>> toListSlackMem a :: ([Word64], [Word8])+-- ([506097522914230528],[8,9,10])+--+-- @since 0.1.0+toListSlackMem ::+ forall e mr. (MemRead mr, Prim e)+ => mr+ -> ([e], [Word8])+toListSlackMem mem =+ (build (\c n -> foldrCountMem k c n mem), getSlack (k8 + r8) [])+ where+ (k, Count r8) = countRemMem mem+ Count k8 = toByteCount k+ getSlack i !acc+ | i == k8 = acc+ | otherwise =+ let i' = i - 1+ in getSlack i' (indexByteOffMem mem (Off i') : acc)+{-# INLINABLE toListSlackMem #-}++-- | Right fold that is useful for converting to a list while tapping into list fusion.+--+-- [Unsafe] Supplying Count larger than memory holds will result in reading out of bounds+-- and a potential segfault.+--+-- @since 0.1.0+foldrCountMem :: forall e b mr. (MemRead mr, Prim e) => Count e -> (e -> b -> b) -> b -> mr -> b+foldrCountMem (Count k) c nil bs = go 0+ where+ go i+ | i == k = nil+ | otherwise =+ let !v = indexOffMem bs (Off i)+ in v `c` go (i + 1)+{-# INLINE[0] foldrCountMem #-}++---------------+-- From List --+---------------++-- Pure immutable conversion --++-- | Just like `fromListMemN`, except it ensures safety by using the length of the+-- list for allocation. Because it has to figure out the length of the list first it+-- will be just a little bit slower, but that much safer.+--+-- ====__Examples__+--+-- >>> import Data.Prim.Memory+-- >>> :set -XDataKinds+-- >>> fromListMem "Hi" :: Bytes 'Inc+-- [0x48,0x00,0x00,0x00,0x69,0x00,0x00,0x00]+--+-- @since 0.1.0+fromListMem ::+ forall e ma. (Prim e, MemAlloc ma)+ => [e]+ -> FrozenMem ma+fromListMem xs =+ let count = coerce (length xs) `countForProxyTypeOf` xs+ in createMemST_ count (loadListMemN_ count xs)+{-# INLINE fromListMem #-}+++-- | Same as `fromListMem` but restricted to a list of `Word8`. Load a list of bytes into+-- a newly allocated memory region. Equivalent to `Data.ByteString.pack` for+-- `Data.ByteString.ByteString`+--+-- ====__Examples__+--+-- >>> fromByteListMem [0..10] :: Bytes 'Pin+-- [0x00,0x01,0x02,0x03,0x04,0x05,0x06,0x07,0x08,0x09,0x0a]+--+-- @since 0.1.0+fromByteListMem ::+ forall ma. MemAlloc ma+ => [Word8]+ -> FrozenMem ma+fromByteListMem = fromListMem+{-# INLINE fromByteListMem #-}+++-- | Similarly to `fromListMem` load a list into a newly allocated memory region, but+-- unlike the aforementioned function it also accepts a hint of how many elements is+-- expected to be in the list. Because the number of expected an actual elements might+-- not match we return not only the frozen memory region, but also:+--+-- * either a list with leftover elements from the input @list@, if it did not fully fit+-- into the allocated region. An empty list would indicate that it did fit exactly.+--+-- @+-- unCount memCount <= length list+-- @+--+-- * or an exact count of how many elements have been loaded when there was no+-- enough elements in the list+--+--+-- In the latter case a zero value would indicate that the list did fit into the newly+-- allocated memory region exactly, which is perfectly fine. But a positive value would+-- mean that the tail of the memory region is still unset and might contain garbage+-- data. Make sure to overwrite the surplus memory yourself or use the safe version+-- `fromListZeroMemN` that fills the surplus with zeros.+--+-- [Unsafe] Whenever @memCount@ precodition is violated, because on each call with the+-- same input it can produce different output therefore it will break referential+-- transparency.+--+-- ====__Examples__+--+-- >>> :set -XTypeApplications+-- >>> fromListMemN @Char @(MBytes 'Inc) 3 "Hello"+-- (Left "lo",[0x48,0x00,0x00,0x00,0x65,0x00,0x00,0x00,0x6c,0x00,0x00,0x00])+-- >>> fromListMemN @Char @(MBytes 'Inc) 2 "Hi"+-- (Left "",[0x48,0x00,0x00,0x00,0x69,0x00,0x00,0x00])+-- >>> fst $ fromListMemN @Char @(MBytes 'Inc) 5 "Hi"+-- Right (Count {unCount = 2})+--+-- @since 0.2.0+fromListMemN ::+ forall e ma. (Prim e, MemAlloc ma)+ => Count e+ -- ^ /memCount/ - Expected number of elements in the list, which exactly how much+ -- memory will be allocated.+ --+ -- /__Preconditions:__/+ --+ -- > 0 <= memCount+ -- > unCount memCount <= length list+ -> [e]+ -- ^ /list/ - A list of elements to load into the newly allocated memory region.+ -> (Either [e] (Count e), FrozenMem ma)+fromListMemN count xs =+ createMemST count $ \mm -> do+ (ys, loadedCount) <- loadListOffMemN count xs mm 0+ pure $+ if loadedCount /= count && null ys+ then Right loadedCount+ else Left ys+{-# INLINE fromListMemN #-}+++-- | Just like `fromListMemN`, except it ensures safety by filling tail with zeros,+-- whenever the list is not long enough.+--+-- ====__Examples__+--+-- >>> import Data.Prim.Memory+-- >>> :set -XTypeApplications+-- >>> fromListZeroMemN @Char @(MBytes 'Inc) 3 "Hi"+-- (Right (Count {unCount = 2}),[0x48,0x00,0x00,0x00,0x69,0x00,0x00,0x00,0x00,0x00,0x00,0x00])+--+-- @since 0.2.0+fromListZeroMemN ::+ forall e ma. (Prim e, MemAlloc ma)+ => Count e -- ^ /memCount/ - Number of elements to load from the list.+ -> [e]+ -> (Either [e] (Count e), FrozenMem ma)+fromListZeroMemN count xs =+ createMemST (max 0 count) $ \mm -> do+ (ys, loadedCount) <- loadListOffMemN count xs mm 0+ let loadedByteCount = toByteCount loadedCount+ surplusByteCount = toByteCount count - loadedByteCount+ when (surplusByteCount > 0) $ setMem mm (countToOff loadedByteCount) surplusByteCount 0+ pure $+ if loadedCount /= count && null ys+ then Right loadedCount+ else Left ys+{-# INLINE fromListZeroMemN #-}++-- | Same as `fromListZeroMemN`, but ignore the extra information about how the loading went.+--+-- ====__Examples__+--+-- >>> import Data.Prim.Memory+-- >>> fromListZeroMemN_ 3 "Hi" :: Bytes 'Inc+-- [0x48,0x00,0x00,0x00,0x69,0x00,0x00,0x00,0x00,0x00,0x00,0x00]+--+-- @since 0.2.0+fromListZeroMemN_ ::+ forall e ma. (Prim e, MemAlloc ma)+ => Count e+ -> [e]+ -> FrozenMem ma+fromListZeroMemN_ !n = snd . fromListZeroMemN n+{-# INLINE fromListZeroMemN_ #-}++++-- Mutable loading --+++loadListByteOffHelper ::+ (MemWrite mw, MonadPrim s m, Prim e)+ => [e]+ -> mw s+ -> Off Word8 -- ^ Offset+ -> Off Word8 -- ^ Upper bound+ -> Off Word8 -- ^ Element size+ -> m ([e], Count e)+loadListByteOffHelper ys mw byteOff k step =+ let go [] i = pure ([], toLoadedCount i)+ go a@(x:xs) i+ | i < k = writeByteOffMem mw i x >> go xs (i + step)+ | otherwise = pure (a, toLoadedCount i)+ toLoadedCount i = fromByteCount (offToCount (i - byteOff))+ in go ys byteOff+{-# INLINE loadListByteOffHelper #-}+++-- | Load elements from the supplied list into a mutable memory region. Loading will+-- start at the supplied offset in number of bytes and will stop when either supplied+-- @elemCount@ number is reached or there are no more elements left in the list to+-- load. This action returns a list of elements that did not get loaded and the count of+-- how many elements did get loaded.+--+-- [Unsafe] When any precondition for either the offset @memTargetOff@ or the element+-- count @memCount@ is violated then a call to this function can result in heap corruption+-- or failure with a segfault.+--+-- ====__Examples__+--+-- For example load the @"Hell"@ somewhere in the middle of `MBytes`:+--+-- >>> ma <- allocZeroMem (6 :: Count Char) :: IO (MBytes 'Inc RW)+-- >>> loadListByteOffMemN 4 "Hello!" ma (toByteOff (1 :: Off Char))+-- ("o!",Count {unCount = 4})+-- >>> freezeMem ma+-- [0x00,0x00,0x00,0x00,0x48,0x00,0x00,0x00,0x65,0x00,0x00,0x00,0x6c,0x00,0x00,0x00,0x6c,0x00,0x00,0x00,0x00,0x00,0x00,0x00]+--+-- Or something more usful like loading prefixes from nested lists:+--+-- >>> import Control.Monad+-- >>> foldM_ (\o xs -> (+ o) . countToByteOff . snd <$> loadListByteOffMemN 4 xs ma o) 2 [[x..] | x <- [1..5] :: [Word8]]+-- >>> freezeMem ma+-- [0x00,0x00,0x01,0x02,0x03,0x04,0x02,0x03,0x04,0x05,0x03,0x04,0x05,0x06,0x04,0x05,0x06,0x07,0x05,0x06,0x07,0x08,0x00,0x00]+--+-- @since 0.2.0+loadListByteOffMemN ::+ (MemWrite mw, MonadPrim s m, Prim e)+ => Count e+ -- ^ /elemCount/ - Maximum number of elements to load from list into the memory region+ --+ -- /__Preconditions:__/+ --+ -- > 0 <= memCount+ --+ -- Target memory region must have enough memory to perform loading of @elemCount@+ -- elements starting at the @memTargetOff@ offset. For types that also implement+ -- `MemAlloc` this can be described as:+ --+ -- > targetByteCount <- getByteCountMem memTarget+ -- > unOff memTargetOff + unCountBytes elemCount <= unCount (targetByteCount - byteCountType @e)+ -> [e] -- ^ /listSource/ - List with elements that should be loaded+ -> mw s -- ^ /memTarget/ - Memory region where to load the elements into+ -> Off Word8+ -- ^ /memTargetOff/ - Offset in number of bytes into target memory where writing will start+ --+ -- /__Preconditions:__/+ --+ -- > 0 <= memTargetOff+ --+ -- Once the pointer is advanced by @memTargetOff@ it must still refer to the same memory+ -- region @memTarget@. For types that also implement `MemAlloc` this can be described+ -- as:+ --+ -- > targetByteCount <- getByteCountMem memTarget+ -- > unOff memTargetOff <= unCount (targetByteCount - byteCountType @e)+ -> m ([e], Count e)+ -- ^ Leftover part of the @listSource@ if any and the exact count of elements that have been loaded.+loadListByteOffMemN count ys mw byteOff = loadListByteOffHelper ys mw byteOff k step+ where+ k = byteOff + countToOff (toByteCount count)+ step = countToOff $ byteCountProxy ys+{-# INLINABLE loadListByteOffMemN #-}++-- | Same as `loadListByteOffMemN`, but infer the count from number of bytes that is+-- available in the target memory region.+--+-- [Unsafe] When a precondition for the element count @memCount@ is violated then a call+-- to this function can result in heap corruption or failure with a segfault.+--+-- ====__Examples__+--+-- >>> :set -XDataKinds+-- >>> import Data.Prim.Memory+-- >>> ma <- allocZeroMem (5 :: Count Char) :: IO (MBytes 'Inc RW)+-- >>> freezeMem ma+-- [0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00]+-- >>> loadListByteOffMem "Hello World" ma 0+-- (" World",Count {unCount = 5})+-- >>> freezeMem ma+-- [0x48,0x00,0x00,0x00,0x65,0x00,0x00,0x00,0x6c,0x00,0x00,0x00,0x6c,0x00,0x00,0x00,0x6f,0x00,0x00,0x00]+-- >>> loadListByteOffMem ([0xff,0xff,0xff] :: [Word8]) ma 1+-- ([],Count {unCount = 3})+-- >>> freezeMem ma+-- [0x48,0xff,0xff,0xff,0x65,0x00,0x00,0x00,0x6c,0x00,0x00,0x00,0x6c,0x00,0x00,0x00,0x6f,0x00,0x00,0x00]+--+-- @since 0.2.0+loadListByteOffMem ::+ (MemAlloc ma, MonadPrim s m, Prim e)+ => [e] -- ^ /listSource/ - List with elements that should be loaded+ -> ma s -- ^ /memTarget/ - Memory region where to load the elements into+ -> Off Word8+ -- ^ /memTargetOff/ - Offset in number of bytes into target memory where writing will start+ --+ -- /__Preconditions:__/+ --+ -- > 0 <= memTargetOff+ --+ -- Once the pointer is advanced by @memTargetOff@ it must still refer to the same memory+ -- region @memTarget@. For types that also implement `MemAlloc` this can be described+ -- as:+ --+ -- > targetByteCount <- getByteCountMem memTarget+ -- > unOff memTargetOff <= unCount (targetByteCount - byteCountType @e)+ -> m ([e], Count e)+ -- ^ Leftover part of the @listSource@ if any and the exact count of elements that have been loaded.+loadListByteOffMem ys ma byteOff = do+ bCount <- getByteCountMem ma+ let k = countToOff bCount - byteOff+ step = countToOff $ byteCountProxy ys+ loadListByteOffHelper ys ma byteOff k step+{-# INLINABLE loadListByteOffMem #-}++-- | Same as `loadListByteOffMemN`, but works with offset in number of elements instead of+-- bytes.+--+-- [Unsafe] When preconditions for either the offset @memTargetOff@ or the element count+-- @memCount@ is violated then a call to this function can result in heap corruption or+-- failure with a segfault.+--+-- @since 0.2.0+loadListOffMemN ::+ (MemWrite mw, MonadPrim s m, Prim e)+ => Count e+ -- ^ /elemCount/ - Maximum number of elements to load from list into the memory region+ --+ -- /__Preconditions:__/+ --+ -- > 0 <= memCount+ --+ -- Target memory region must have enough memory to perform loading of @elemCount@+ -- elements starting at the @memTargetOff@ offset. For types that also implement+ -- `MemAlloc` this can be described as:+ --+ -- > targetCount <- getCountMem memTarget+ -- > unOff memTargetOff + unCount elemCount < unCount targetCount+ -> [e] -- ^ /listSource/ - List with elements that should be loaded+ -> mw s -- ^ /memTarget/ - Memory region where to load the elements into+ -> Off e+ -- ^ /memTargetOff/ - Offset in number of elements into target memory where writing will start+ --+ -- /__Preconditions:__/+ --+ -- > 0 <= memTargetOff+ --+ -- Once the pointer is advanced by @memTargetOff@ it must still refer to the same memory+ -- region @memTarget@. For types that also implement `MemAlloc` this can be described+ -- as:+ --+ -- > targetCount <- getByteCountMem memTarget+ -- > unOff memTargetOff < unCount targetCount+ -> m ([e], Count e)+ -- ^ Leftover part of the @listSource@ if any and the exact count of elements that have been loaded.+loadListOffMemN count ys mw off =+ let go [] i = pure ([], toLoadedCount i)+ go a@(x:xs) i+ | i < k = writeOffMem mw i x >> go xs (i + 1)+ | otherwise = pure (a, toLoadedCount i)+ k = off + countToOff count+ toLoadedCount i = offToCount (i - off)+ in go ys off+{-# INLINABLE loadListOffMemN #-}+++-- | Same as `loadListOffMemN`, but start loading at @0@ offset.+--+-- [Unsafe] When any precondition for the element count @memCount@ is violated then a call to+-- this function can result in heap corruption or failure with a segfault.+--+-- @since 0.2.0+loadListMemN ::+ forall e mw m s. (MemWrite mw, MonadPrim s m, Prim e)+ => Count e+ -- ^ /elemCount/ - Maximum number of elements to load from list into the memory region+ --+ -- /__Preconditions:__/+ --+ -- > 0 <= memCount+ --+ -- Target memory region must have enough memory to perform loading of @elemCount@+ -- elements. For types that also implement `MemAlloc` this can be described as:+ --+ -- > targetCount <- getCountMem memTarget+ -- > elemCount <= targetCount+ -> [e] -- ^ /listSource/ - List with elements that should be loaded+ -> mw s -- ^ /memTarget/ - Memory region where to load the elements into+ -> m ([e], Count e)+ -- ^ Leftover part of the @listSource@ if any and the exact count of elements that have been loaded.+loadListMemN count xs mw = loadListOffMemN count xs mw 0+{-# INLINABLE loadListMemN #-}++++-- | Same as `loadListMemN`, but ignores the result.+--+-- [Unsafe] When any precondition for the element count @memCount@ is violated then a call+-- to this function can result in heap corruption or failure with a segfault.+--+-- @since 0.2.0+loadListMemN_ ::+ forall e mw m s. (Prim e, MemWrite mw, MonadPrim s m)+ => Count e+ -- ^ /elemCount/ - Maximum number of elements to load from list into the memory region+ --+ -- /__Preconditions:__/+ --+ -- > 0 <= memCount+ --+ -- Target memory region must have enough memory to perform loading of @elemCount@+ -- elements. For types that also implement `MemAlloc` this can be described as:+ --+ -- > targetCount <- getCountMem memTarget+ -- > elemCount <= targetCount+ -> [e] -- ^ /listSource/ - List with elements that should be loaded+ -> mw s -- ^ /memTarget/ - Memory region where to load the elements into+ -> m ()+loadListMemN_ (Count n) ys mb =+ let go [] _ = pure ()+ go (x:xs) i = when (i < n) $ writeOffMem mb (Off i) x >> go xs (i + 1)+ in go ys 0+{-# INLINABLE loadListMemN_ #-}+++++-- | Same as `loadListOffMemN`, but infer the count from number of bytes that is available+-- in the target memory region.+--+-- [Unsafe] When a precondition for the element count @memCount@ is violated then a call+-- to this function can result in heap corruption or failure with a segfault.+--+-- @since 0.2.0+loadListOffMem ::+ forall e ma m s. (Prim e, MemAlloc ma, MonadPrim s m)+ => [e] -- ^ /listSource/ - List with elements that should be loaded+ -> ma s -- ^ /memTarget/ - Memory region where to load the elements into+ -> Off e+ -- ^ /memTargetOff/ - Offset in number of elements into target memory where writing will+ -- start+ --+ -- /__Preconditions:__/+ --+ -- > 0 <= memTargetOff+ --+ -- Once the pointer is advanced by @memTargetOff@ it must still refer to the same memory+ -- region @memTarget@. For types that also implement `MemAlloc` this can be described+ -- as:+ --+ -- > targetCount <- getCountMem memTarget+ -- > unOff memTargetOff < unCount targetCount+ -> m ([e], Count e)+ -- ^ Leftover part of the @listSource@ if any and the exact count of elements that have been loaded.+loadListOffMem ys ma off = getCountMem ma >>= \c -> loadListOffMemN (c - offToCount off) ys ma off+{-# INLINE loadListOffMem #-}+++-- | Same as `loadListMemN`, but tries to fit as many elements as possible into the mutable+-- memory region starting at the beginning. This operation is always safe.+--+-- ====__Examples__+--+-- >>> import Data.Prim.Memory+-- >>> ma <- allocMem (5 :: Count Char) :: IO (MBytes 'Inc RW)+-- >>> loadListMem "HelloWorld" ma+-- ("World",Count {unCount = 5})+-- >>> freezeMem ma+-- [0x48,0x00,0x00,0x00,0x65,0x00,0x00,0x00,0x6c,0x00,0x00,0x00,0x6c,0x00,0x00,0x00,0x6f,0x00,0x00,0x00]+-- >>> loadListMem (replicate 6 (0xff :: Word8)) ma+-- ([],Count {unCount = 6})+-- >>> freezeMem ma+-- [0xff,0xff,0xff,0xff,0xff,0xff,0x00,0x00,0x6c,0x00,0x00,0x00,0x6c,0x00,0x00,0x00,0x6f,0x00,0x00,0x00]+--+-- @since 0.2.0+loadListMem ::+ forall e ma m s. (Prim e, MemAlloc ma, MonadPrim s m)+ => [e] -- ^ /listSource/ - List with elements to load+ -> ma s -- ^ /memTarget/ - Mutable region where to load elements from the list+ -> m ([e], Count e)+ -- ^ Leftover part of the @listSource@ if any and the exact count of elements that have been loaded.+loadListMem ys ma = getCountMem ma >>= \c -> loadListOffMemN (c `countForProxyTypeOf` ys) ys ma 0+{-# INLINE loadListMem #-}++-- | Same as `loadListMem`, but ignores the result. Equivalence as property:+--+-- prop> let c = fromInteger (abs i) :: Count Int in (createZeroMemST_ c (loadListMem_ (xs :: [Int])) :: Bytes 'Inc) == createZeroMemST_ c (void . loadListMem xs)+--+-- @since 0.2.0+loadListMem_ ::+ forall e ma m s. (Prim e, MemAlloc ma, MonadPrim s m)+ => [e] -- ^ /listSource/ - List with elements to load+ -> ma s -- ^ /memTarget/ - Mutable region where to load elements from the list+ -> m ()+loadListMem_ ys mb = getCountMem mb >>= \c -> loadListMemN_ (c `countForProxyTypeOf` ys) ys mb+{-# INLINE loadListMem_ #-}+++-- | Convert a memory region to a list of bytes. Equivalent to `Data.ByteString.unpack`+-- for `Data.ByteString.ByteString`+--+-- ====__Example__+--+-- >>> toByteListMem (fromByteListMem [0..10] :: Bytes 'Pin)+-- [0,1,2,3,4,5,6,7,8,9,10]+--+-- @since 0.1.0+toByteListMem ::+ forall ma. MemAlloc ma+ => FrozenMem ma+ -> [Word8]+toByteListMem = toListMem+{-# INLINE toByteListMem #-}++-- mapMem ::+-- forall e e' mr ma. (MemRead mr, MemAlloc ma, Prim e, Prim e')+-- => (e -> e')+-- -> mr+-- -> (FrozenMem ma, [Word8])+-- mapMem f = undefined+++mapByteMem ::+ forall e mr ma. (MemRead mr, MemAlloc ma, Prim e)+ => (Word8 -> e)+ -> mr+ -> FrozenMem ma+mapByteMem f = imapByteOffMem (const f)++-- Map an index aware function over memory region+--+-- >>> import Data.Prim.Memory+-- >>> a = fromListMem [1 .. 10 :: Word8] :: Bytes 'Inc+-- >>> a+-- [0x01,0x02,0x03,0x04,0x05,0x06,0x07,0x08,0x09,0x0a]+-- >>> imapByteOffMem (\i e -> (fromIntegral i :: Int8, e + 0xf0)) a :: Bytes 'Pin+-- [0x00,0xf1,0x01,0xf2,0x02,0xf3,0x03,0xf4,0x04,0xf5,0x05,0xf6,0x06,0xf7,0x07,0xf8,0x08,0xf9,0x09,0xfa]+--+-- @since 0.1.0+imapByteOffMem ::+ (MemRead mr, MemAlloc ma, Prim e) => (Off Word8 -> Word8 -> e) -> mr -> FrozenMem ma+imapByteOffMem f r = runST $ mapByteOffMemM (\i -> pure . f i) r++-- @since 0.1.0+mapByteMemM ::+ (MemRead mr, MemAlloc ma, MonadPrim s m, Prim e)+ => (Word8 -> m e)+ -> mr+ -> m (FrozenMem ma)+mapByteMemM f = mapByteOffMemM (const f)+++-- @since 0.1.0+mapByteOffMemM ::+ forall e mr ma m s. (MemRead mr, MemAlloc ma, MonadPrim s m, Prim e)+ => (Off Word8 -> Word8 -> m e)+ -> mr+ -> m (FrozenMem ma)+mapByteOffMemM f r = do+ let bc@(Count n) = byteCountMem r+ c = Count n `countForProxyTypeOf` f 0 0+ mem <- allocMem c+ _ <- forByteOffMemM_ r 0 bc f+ -- let go i =+ -- when (i < n) $ do+ -- f i (indexByteOffMem r (Off i)) >>=+ -- writeOffMem mem (offAsProxy c (Off i))+ -- go (i + 1)+ -- go 0+ freezeMem mem+++-- | Iterate over a region of memory+forByteOffMemM_ ::+ (MemRead mr, MonadPrim s m, Prim e)+ => mr+ -> Off Word8+ -> Count e+ -> (Off Word8 -> e -> m b)+ -> m (Off Word8)+forByteOffMemM_ r (Off byteOff) c f =+ let n = coerce (toByteCount c) + byteOff+ Count k = byteCountProxy c+ go i+ | i < n = f (Off i) (indexByteOffMem r (Off i)) >> go (i + k)+ | otherwise = pure $ Off i+ in go byteOff++loopShortM :: Monad m => Int -> (Int -> a -> Bool) -> (Int -> Int) -> a -> (Int -> a -> m a) -> m a+loopShortM !startAt condition increment !initAcc f = go startAt initAcc+ where+ go !step !acc+ | condition step acc = f step acc >>= go (increment step)+ | otherwise = pure acc+{-# INLINE loopShortM #-}++loopShortM' :: Monad m => Int -> (Int -> a -> m Bool) -> (Int -> Int) -> a -> (Int -> a -> m a) -> m a+loopShortM' !startAt condition increment !initAcc f = go startAt initAcc+ where+ go !step !acc =+ condition step acc >>= \cont ->+ if cont+ then f step acc >>= go (increment step)+ else pure acc+{-# INLINE loopShortM' #-}++-- -- | Iterate over a region of memory+-- loopMemM_ ::+-- (MemRead mr, MonadPrim s m, Prim e)+-- => r+-- -> Off Word8+-- -> Count e+-- -> (Count Word8 -> a -> Bool)+-- -> (Off Word8 -> e -> m b)+-- -> m (Off Word8)+-- foldlByteOffMemM_ r (Off byteOff) c f =+-- loopShortM byteOff (\i -> f (coerce i))+-- let n = coerce (toByteCount c) + byteOff+-- Count k = byteCountProxy c+-- go i+-- | i < n = f (Off i) (indexByteOffMem r (Off i)) >> go (i + k)+-- | otherwise = pure $ Off i+-- in go byteOff+++data MemView a = MemView+ { mvOffset :: {-# UNPACK #-} !(Off Word8)+ , mvCount :: {-# UNPACK #-} !(Count Word8)+ , mvMem :: !a+ }++data MMemView a s = MMemView+ { mmvOffset :: {-# UNPACK #-} !(Off Word8)+ , mmvCount :: {-# UNPACK #-} !(Count Word8)+ , mmvMem :: !(a s)+ }++izipWithByteOffMemM_ ::+ (MemRead mr1, MemRead mr2, MonadPrim s m, Prim e)+ => mr1+ -> Off Word8+ -> mr2+ -> Off Word8+ -> Count e+ -> (Off Word8 -> e -> Off Word8 -> e -> m b)+ -> m (Off Word8)+izipWithByteOffMemM_ r1 (Off byteOff1) r2 off2 c f =+ let n = coerce (toByteCount c) + byteOff1+ Count k = byteCountProxy c+ go i+ | i < n =+ let o1 = Off i+ o2 = Off i + off2+ in f o1 (indexByteOffMem r1 o1) o2 (indexByteOffMem r2 o2) >>+ go (i + k)+ | otherwise = pure $ Off i+ in go byteOff1+++izipWithOffMemM_ ::+ (MemRead mr1, MemRead mr2, MonadPrim s m, Prim e1, Prim e2)+ => mr1+ -> Off e1+ -> mr2+ -> Off e2+ -> Int+ -> (Off e1 -> e1 -> Off e2 -> e2 -> m b)+ -> m ()+izipWithOffMemM_ r1 off1 r2 off2 nc f =+ let n = nc + coerce off1+ go o1@(Off i) o2 =+ when (i < n) $+ f o1 (indexOffMem r1 o1) o2 (indexOffMem r2 o2) >> go (o1 + 1) (o2 + 1)+ in go off1 off2+++-- class Mut f => MFunctor f where+-- mmap :: (Elt f a, Elt f b, MonadPrim s m) => (a -> b) -> f a s -> m (f b s)++-- class Mut f => MTraverse f where+-- mmapM :: (Elt f a, Elt f b, MonadPrim s m) => (a -> m b) -> f a s -> m (f b s)++-- class MFunctor f => MApplicative f where+-- pureMut :: (Elt f a, MonadPrim s m) => a -> m (f a s)+-- liftMut ::+-- (Elt f a, Elt f b, Elt f c, MonadPrim s m) => (a -> b -> m c) -> f a s -> f b s -> m (f c s)++-- class MApplicative f => MMonad f where+-- bindMut ::+-- (Elt f a, Elt f b, MonadPrim s m) => f a s -> (a -> m b) -> f b s -> m (f c s)++-- instance MFunctor MAddr where+-- mmap f maddr = do+-- Count n <- getCountMAddr maddr+-- maddr' <- allocMAddr (Count n)+-- let go i =+-- when (i < n) $ do+-- writeOffMAddr maddr' (Off i) . f =<< readOffMAddr maddr (Off i)+-- go (i + 1)+-- maddr' <$ go 0++-- instance MTraverse MAddr where+-- mmapM f maddr = do+-- Count n <- getCountMAddr maddr+-- maddr' <- allocMAddr (Count n)+-- let go i =+-- when (i < n) $ do+-- writeOffMAddr maddr' (Off i) =<< f =<< readOffMAddr maddr (Off i)+-- go (i + 1)+-- maddr' <$ go 0+++---------------------+-- Bytes instances --+---------------------++instance MemRead (Bytes p) where+ byteCountMem = byteCountBytes+ {-# INLINE byteCountMem #-}+ indexOffMem = indexOffBytes+ {-# INLINE indexOffMem #-}+ indexByteOffMem = indexByteOffBytes+ {-# INLINE indexByteOffMem #-}+ copyByteOffToMBytesMem = copyByteOffBytesToMBytes+ {-# INLINE copyByteOffToMBytesMem #-}+ copyByteOffToPtrMem = copyByteOffBytesToPtr+ {-# INLINE copyByteOffToPtrMem #-}+ compareByteOffToPtrMem bytes1 off1 ptr2 off2 c =+ pure $! compareByteOffBytesToPtr bytes1 off1 ptr2 off2 c+ {-# INLINE compareByteOffToPtrMem #-}+ compareByteOffToBytesMem bytes1 off1 bytes2 off2 c =+ compareByteOffBytes bytes1 off1 bytes2 off2 c+ {-# INLINE compareByteOffToBytesMem #-}+ compareByteOffMem mem1 off1 bs off2 c =+ compareByteOffToBytesMem mem1 off1 bs off2 c+ {-# INLINE compareByteOffMem #-}++instance Typeable p => MemAlloc (MBytes p) where+ type FrozenMem (MBytes p) = Bytes p+ getByteCountMem = getByteCountMBytes+ {-# INLINE getByteCountMem #-}+ allocMem = allocMBytes+ {-# INLINE allocMem #-}+ thawMem = thawBytes+ {-# INLINE thawMem #-}+ freezeMem = freezeMBytes+ {-# INLINE freezeMem #-}+ resizeMem = reallocMBytes+ {-# INLINE resizeMem #-}++instance MemWrite (MBytes p) where+ readOffMem = readOffMBytes+ {-# INLINE readOffMem #-}+ readByteOffMem = readByteOffMBytes+ {-# INLINE readByteOffMem #-}+ writeOffMem = writeOffMBytes+ {-# INLINE writeOffMem #-}+ writeByteOffMem = writeByteOffMBytes+ {-# INLINE writeByteOffMem #-}+ moveByteOffToPtrMem = moveByteOffMBytesToPtr+ {-# INLINE moveByteOffToPtrMem #-}+ moveByteOffToMBytesMem = moveByteOffMBytesToMBytes+ {-# INLINE moveByteOffToMBytesMem #-}+ moveByteOffMem = moveByteOffToMBytesMem+ {-# INLINE moveByteOffMem #-}+ copyByteOffMem = copyByteOffToMBytesMem+ {-# INLINE copyByteOffMem #-}+ setMem = setMBytes+ {-# INLINE setMem #-}+++instance Show (Bytes p) where+ show b =+ Foldable.foldr' ($) "]" $+ ('[' :) : List.intersperse (',' :) (map (("0x" ++) .) (showsHexMem b))++instance Typeable p => IsList (Bytes p) where+ type Item (Bytes p) = Word8+ fromList = fromListMem+ {-# INLINE fromList #-}+ fromListN n = fromListZeroMemN_ (Count n)+ {-# INLINE fromListN #-}+ toList = toListMem+ {-# INLINE toList #-}++instance Eq (Bytes p) where+ b1 == b2 = isSameBytes b1 b2 || eqMem b1 b2+ {-# INLINE (==) #-}++instance Ord (Bytes p) where+ compare b1 b2 =+ compare n (byteCountBytes b2) <> compareByteOffBytes b1 0 b2 0 n+ where+ n = byteCountBytes b1+ {-# INLINE compare #-}++instance Typeable p => Semigroup.Semigroup (Bytes p) where+ (<>) = appendMem+ {-# INLINE (<>) #-}+ sconcat (x :| xs) = concatMem (x:xs)+ {-# INLINE sconcat #-}+ stimes i = cycleMemN (fromIntegral i)+ {-# INLINE stimes #-}++instance Typeable p => Monoid.Monoid (Bytes p) where+ mappend = appendMem+ {-# INLINE mappend #-}+ mconcat = concatMem+ {-# INLINE mconcat #-}+ mempty = emptyMem+ {-# INLINE mempty #-}+++-- | A list of `ShowS` which covert bytes to base16 encoded strings. Each element of the list+-- is a function that will convert one byte.+--+-- ====__Example__+--+-- >>> :set -XDataKinds+-- >>> import Data.Prim.Memory+-- >>> concatMap ($ " ") $ showsHexMem (fromListMem [1 :: Int16 .. 15] :: Bytes 'Inc)+-- "01 00 02 00 03 00 04 00 05 00 06 00 07 00 08 00 09 00 0a 00 0b 00 0c 00 0d 00 0e 00 0f 00 "+--+-- @since 0.1.0+showsHexMem :: MemRead mr => mr -> [ShowS]+showsHexMem b = map toHex (toListMem b :: [Word8])+ where+ toHex b8 =+ (if b8 <= 0x0f+ then ('0' :)+ else id) .+ showHex b8++-- | Ensure that memory is filled with zeros before and after it gets used. `PtrAccess` is+-- not used directly, but istead is used to guarantee that the memory is pinned and its+-- contents do get moved around by the garbage collector.+--+-- @since 0.2.0+withScrubbedMem ::+ forall e ma m a.+ (MonadUnliftPrim RW m, Prim e, MemAlloc ma, PtrAccess RW (ma RW))+ => Count e+ -> (ma RW -> m a)+ -> m a+withScrubbedMem c f = do+ mem <- allocZeroMem c+ let _fptr = toForeignPtr mem :: IO (ForeignPtr e) -- Force the `PtrAccess` constraint.+ f mem `finallyPrim` setMem mem 0 (toByteCount c) 0+ where+ finallyPrim m1 m2 = withRunInPrimBase $ \run -> finally (run m1) (run m2)+{-# INLINE withScrubbedMem #-}
+ src/Data/Prim/Memory/PrimArray.hs view
@@ -0,0 +1,310 @@+{-# LANGUAGE DataKinds #-}+{-# LANGUAGE FlexibleContexts #-}+{-# LANGUAGE FlexibleInstances #-}+{-# LANGUAGE GeneralizedNewtypeDeriving #-}+{-# LANGUAGE MultiParamTypeClasses #-}+{-# LANGUAGE RankNTypes #-}+{-# LANGUAGE RoleAnnotations #-}+{-# LANGUAGE ScopedTypeVariables #-}+{-# LANGUAGE TypeFamilies #-}+-- |+-- Module : Data.Prim.Memory.PrimArray+-- Copyright : (c) Alexey Kuleshevich 2020+-- License : BSD3+-- Maintainer : Alexey Kuleshevich <alexey@kuleshevi.ch>+-- Stability : experimental+-- Portability : non-portable+--+module Data.Prim.Memory.PrimArray+ ( PrimArray(..)+ , MPrimArray(..)+ , Pinned(..)+ , fromBytesPrimArray+ , toBytesPrimArray+ , castPrimArray+ , fromMBytesMPrimArray+ , toMBytesMPrimArray+ , castMPrimArray+ , allocMPrimArray+ , allocPinnedMPrimArray+ , allocAlignedMPrimArray+ , allocUnpinnedMPrimArray+ , shrinkMPrimArray+ , resizeMPrimArray+ , reallocMPrimArray+ , isPinnedPrimArray+ , isPinnedMPrimArray++ , thawPrimArray+ , freezeMPrimArray+ , sizePrimArray+ , getSizeMPrimArray+ , readMPrimArray+ , writeMPrimArray++ , setMPrimArray+ , copyPrimArrayToMPrimArray+ , moveMPrimArrayToMPrimArray+ ) where++import Control.DeepSeq+import Control.Prim.Monad+import Foreign.Prim+import Data.Prim+import Data.Prim.Memory.Bytes+import Data.Prim.Memory.Internal+import Data.Prim.Memory.ForeignPtr+++-- | An immutable array of bytes of type @e@+newtype PrimArray (p :: Pinned) e = PrimArray (Bytes p)+ deriving (NFData, Semigroup, Monoid, MemRead)+type role PrimArray nominal nominal++-- | A mutable array of bytes of type @e@+newtype MPrimArray (p :: Pinned) e s = MPrimArray (MBytes p s)+ deriving (NFData, MemWrite)+type role MPrimArray nominal nominal nominal++-- | Read-only access, but it is not enforced.+instance PtrAccess s (PrimArray 'Pin e) where+ toForeignPtr = pure . toForeignPtrBytes . toBytesPrimArray+ {-# INLINE toForeignPtr #-}+ withPtrAccess b = withPtrBytes (toBytesPrimArray b)+ {-# INLINE withPtrAccess #-}+ withNoHaltPtrAccess b = withNoHaltPtrBytes (toBytesPrimArray b)+ {-# INLINE withNoHaltPtrAccess #-}++instance PtrAccess s (MPrimArray 'Pin e s) where+ toForeignPtr = pure . toForeignPtrMBytes . toMBytesMPrimArray+ {-# INLINE toForeignPtr #-}+ withPtrAccess mb = withPtrMBytes (toMBytesMPrimArray mb)+ {-# INLINE withPtrAccess #-}+ withNoHaltPtrAccess mb = withNoHaltPtrMBytes (toMBytesMPrimArray mb)+ {-# INLINE withNoHaltPtrAccess #-}++instance Typeable p => MemAlloc (MPrimArray p e) where+ type FrozenMem (MPrimArray p e) = PrimArray p e+ getByteCountMem = getByteCountMem . toMBytesMPrimArray+ {-# INLINE getByteCountMem #-}+ allocMem = fmap fromMBytesMPrimArray . allocMBytes+ {-# INLINE allocMem #-}+ thawMem = thawPrimArray+ {-# INLINE thawMem #-}+ freezeMem = freezeMPrimArray+ {-# INLINE freezeMem #-}+ resizeMem mba = fmap fromMBytesMPrimArray . reallocMBytes (toMBytesMPrimArray mba)+ {-# INLINE resizeMem #-}++instance (Typeable p, Prim e) => IsList (PrimArray p e) where+ type Item (PrimArray p e) = e+ fromList = fromListMem+ fromListN n = fromListZeroMemN_ (Count n)+ toList = toListMem++instance Typeable p => IsString (PrimArray p Char) where+ fromString = fromListMem++instance (Show e, Prim e) => Show (PrimArray p e) where+ show = show . toListPrimArray+++toListPrimArray :: Prim e => PrimArray p e -> [e]+toListPrimArray = toListMem++castPrimArray :: PrimArray p e' -> PrimArray p e+castPrimArray = coerce++fromBytesPrimArray :: Bytes p -> PrimArray p e+fromBytesPrimArray = coerce++toBytesPrimArray :: PrimArray p e -> Bytes p+toBytesPrimArray = coerce++castMPrimArray :: MPrimArray p e' s -> MPrimArray p e s+castMPrimArray = coerce++fromMBytesMPrimArray :: MBytes p s -> MPrimArray p e s+fromMBytesMPrimArray = coerce++toMBytesMPrimArray :: MPrimArray p e s -> MBytes p s+toMBytesMPrimArray = coerce++sizePrimArray :: forall e p. Prim e => PrimArray p e -> Size+sizePrimArray = (coerce :: Count e -> Size) . countBytes . toBytesPrimArray+{-# INLINE sizePrimArray #-}++getSizeMPrimArray :: forall e p m s. (MonadPrim s m, Prim e) => MPrimArray p e s -> m Size+getSizeMPrimArray = fmap (coerce :: Count e -> Size) . getCountMBytes . toMBytesMPrimArray+{-# INLINE getSizeMPrimArray #-}++allocMPrimArray ::+ forall e p m s . (Typeable p, Prim e, MonadPrim s m) => Size -> m (MPrimArray p e s)+allocMPrimArray sz = fromMBytesMPrimArray <$> allocMBytes (coerce sz :: Count e)+{-# INLINE allocMPrimArray #-}++allocUnpinnedMPrimArray :: forall e m s . (MonadPrim s m, Prim e) => Size -> m (MPrimArray 'Inc e s)+allocUnpinnedMPrimArray sz = fromMBytesMPrimArray <$> allocUnpinnedMBytes (coerce sz :: Count e)+{-# INLINE allocUnpinnedMPrimArray #-}++allocPinnedMPrimArray :: forall e m s . (MonadPrim s m, Prim e) => Size -> m (MPrimArray 'Pin e s)+allocPinnedMPrimArray sz = fromMBytesMPrimArray <$> allocPinnedMBytes (coerce sz :: Count e)+{-# INLINE allocPinnedMPrimArray #-}++allocAlignedMPrimArray ::+ (MonadPrim s m, Prim e)+ => Count e -- ^ Size in number of bytes+ -> m (MPrimArray 'Pin e s)+allocAlignedMPrimArray = fmap fromMBytesMPrimArray . allocAlignedMBytes+{-# INLINE allocAlignedMPrimArray #-}++freezeMPrimArray :: MonadPrim s m => MPrimArray p e s -> m (PrimArray p e)+freezeMPrimArray = fmap fromBytesPrimArray . freezeMBytes . toMBytesMPrimArray+{-# INLINE freezeMPrimArray #-}++thawPrimArray :: MonadPrim s m => PrimArray p e -> m (MPrimArray p e s)+thawPrimArray = fmap fromMBytesMPrimArray . thawBytes . toBytesPrimArray+{-# INLINE thawPrimArray #-}++-- | Shrink mutable bytes to new specified count of elements. The new count must be less+-- than or equal to the current count as reported by `getCountMPrimArray`.+shrinkMPrimArray ::+ forall e p m s. (MonadPrim s m, Prim e)+ => MPrimArray p e s+ -> Size+ -> m ()+shrinkMPrimArray mba sz = shrinkMBytes (toMBytesMPrimArray mba) (coerce sz :: Count e)+{-# INLINE shrinkMPrimArray #-}+++-- | Attempt to resize mutable bytes in place.+--+-- * New bytes might be allocated, with the copy of an old one.+-- * Old references should not be kept around to allow GC to claim it+-- * Old references should not be used to avoid undefined behavior+resizeMPrimArray ::+ forall e p m s. (MonadPrim s m, Prim e)+ => MPrimArray p e s+ -> Size+ -> m (MPrimArray 'Inc e s)+resizeMPrimArray mba sz =+ fromMBytesMPrimArray <$>+ resizeMBytes (toMBytesMPrimArray mba) (coerce sz :: Count e)+{-# INLINE resizeMPrimArray #-}++reallocMPrimArray ::+ forall e p m s. (MonadPrim s m, Typeable p, Prim e)+ => MPrimArray p e s+ -> Size+ -> m (MPrimArray p e s)+reallocMPrimArray mba sz =+ fromMBytesMPrimArray <$>+ reallocMBytes (toMBytesMPrimArray mba) (coerce sz :: Count e)+{-# INLINABLE reallocMPrimArray #-}+++isPinnedPrimArray :: PrimArray p e -> Bool+isPinnedPrimArray (PrimArray b) = isPinnedBytes b+{-# INLINE isPinnedPrimArray #-}++isPinnedMPrimArray :: MPrimArray p e s -> Bool+isPinnedMPrimArray (MPrimArray mb) = isPinnedMBytes mb+{-# INLINE isPinnedMPrimArray #-}++readMPrimArray :: (MonadPrim s m, Prim e) => MPrimArray p e s -> Int -> m e+readMPrimArray (MPrimArray mb) = readOffMBytes mb . coerce+{-# INLINE readMPrimArray #-}++writeMPrimArray :: (MonadPrim s m, Prim e) => MPrimArray p e s -> Int -> e -> m ()+writeMPrimArray (MPrimArray mb) o = writeOffMBytes mb (coerce o)+{-# INLINE writeMPrimArray #-}++++setMPrimArray ::+ forall e p m s. (MonadPrim s m, Prim e)+ => MPrimArray p e s -- ^ Chunk of memory to fill+ -> Int -- ^ Offset in number of elements+ -> Size -- ^ Number of cells to fill+ -> e -- ^ A value to fill the cells with+ -> m ()+setMPrimArray (MPrimArray mb) off sz = setMBytes mb (coerce off) (coerce sz)+{-# INLINE setMPrimArray #-}++copyPrimArrayToMPrimArray ::+ forall e p m s. (MonadPrim s m, Prim e)+ => PrimArray p e+ -> Int+ -> MPrimArray p e s+ -> Int+ -> Size+ -> m ()+copyPrimArrayToMPrimArray ba srcOff mba dstOff sz =+ copyMem ba (coerce srcOff) mba (coerce dstOff) (coerce sz `countForProxyTypeOf` ba)+{-# INLINE copyPrimArrayToMPrimArray #-}++moveMPrimArrayToMPrimArray ::+ forall e p m s. (MonadPrim s m, Prim e)+ => MPrimArray p e s+ -> Int+ -> MPrimArray p e s+ -> Int+ -> Size+ -> m ()+moveMPrimArrayToMPrimArray ba srcOff mba dstOff sz =+ moveMem ba (coerce srcOff) mba (coerce dstOff) (coerce sz :: Count e)+{-# INLINE moveMPrimArrayToMPrimArray #-}++++-- toPtrPrimArray :: PrimArray Pin e -> Ptr e+-- toPtrPrimArray (PrimArray ba#) = Ptr (byteArrayContents# ba#)+-- {-# INLINE toPtrPrimArray #-}++-- toPtrMPrimArray :: MPrimArray Pin e s -> Ptr e+-- toPtrMPrimArray (MPrimArray mba#) = Ptr (mutablePrimArrayContents# mba#)+-- {-# INLINE toPtrMPrimArray #-}++-- -- | Pointer access to immutable `PrimArray` should be for read only purposes, but it is+-- -- not enforced. Any mutation will break referential transparency+-- withPtrPrimArray :: MonadPrim s m => PrimArray Pin e -> (Ptr e -> m b) -> m b+-- withPtrPrimArray b f = do+-- res <- f (toPtrPrimArray b)+-- res <$ touch b+-- {-# INLINE withPtrPrimArray #-}++-- -- | Same as `withPtrPrimArray`, but is suitable for actions that don't terminate+-- withNoHaltPtrPrimArray :: MonadUnliftPrim s m => PrimArray Pin e -> (Ptr e -> m b) -> m b+-- withNoHaltPtrPrimArray b f = withAliveUnliftPrim b $ f (toPtrPrimArray b)+-- {-# INLINE withNoHaltPtrPrimArray #-}++-- withPtrMPrimArray :: MonadPrim s m => MPrimArray Pin e s -> (Ptr e -> m b) -> m b+-- withPtrMPrimArray mb f = do+-- res <- f (toPtrMPrimArray mb)+-- res <$ touch mb+-- {-# INLINE withPtrMPrimArray #-}++-- withNoHaltPtrMPrimArray :: MonadUnliftPrim s m => MPrimArray Pin e s -> (Ptr e -> m b) -> m b+-- withNoHaltPtrMPrimArray mb f = withAliveUnliftPrim mb $ f (toPtrMPrimArray mb)+-- {-# INLINE withNoHaltPtrMPrimArray #-}+++-- -- -- | Check if two byte arrays refer to pinned memory and compare their pointers.+-- -- isSamePrimArray :: PrimArray p1 e -> PrimArray p2 e -> Bool+-- -- isSamePrimArray (PrimArray b1#) (PrimArray b2#) = isTrue# (isSameByteArray# b1# b2#)+-- -- {-# INLINE[0] isSamePrimArray #-}+-- -- {-# RULES+-- -- "isSamePinnedPrimArray" isSamePrimArray = isSamePinnedPrimArray+-- -- #-}++-- -- -- | Perform pointer equality on pinned `PrimArray`.+-- -- isSamePinnedPrimArray :: PrimArray Pin e -> PrimArray Pin e -> Bool+-- -- isSamePinnedPrimArray pb e1 pb2 = toPtrPrimArray pb e1 == toPtrPrimArray pb e2+-- -- {-# INLINE isSamePinnedPrimArray #-}++++-- -- byteStringConvertError :: String -> a+-- -- byteStringConvertError msg = error $ "Cannot convert 'ByteString'. " ++ msg+-- -- {-# NOINLINE byteStringConvertError #-}+
src/Data/Prim/Memory/Ptr.hs view
@@ -55,7 +55,7 @@ copyByteOffPtrToMBytes :: (MonadPrim s m, Prim e) => Ptr e -> Off Word8 -> MBytes p s -> Off Word8 -> Count e -> m () copyByteOffPtrToMBytes (Ptr srcAddr#) (Off (I# srcOff#)) (MBytes dst#) (Off (I# dstOff#)) c =- prim_ $ copyAddrToByteArray# (srcAddr# `plusAddr#` srcOff#) dst# dstOff# (fromCount# c)+ prim_ $ copyAddrToByteArray# (srcAddr# `plusAddr#` srcOff#) dst# dstOff# (unCountBytes# c) {-# INLINE copyByteOffPtrToMBytes #-} @@ -79,7 +79,7 @@ src# srcOff# (dstAddr# `plusAddr#` dstOff#)- (fromCount# c)+ (unCountBytes# c) {-# INLINE copyByteOffBytesToPtr #-} @@ -103,7 +103,7 @@ src# srcOff# (dstAddr# `plusAddr#` dstOff#)- (fromCount# c)+ (unCountBytes# c) {-# INLINE copyByteOffMBytesToPtr #-} @@ -122,7 +122,7 @@ -> m () moveByteOffPtrToMBytes (Ptr srcAddr#) (Off (I# srcOff#)) (MBytes dst#) (Off (I# dstOff#)) c = unsafeIOToPrim $- memmoveMutableByteArrayFromAddr# srcAddr# srcOff# dst# dstOff# (fromCount# c)+ memmoveMutableByteArrayFromAddr# srcAddr# srcOff# dst# dstOff# (unCountBytes# c) {-# INLINE moveByteOffPtrToMBytes #-} moveMBytesToPtr :: (MonadPrim s m, Prim e) => MBytes p s -> Off e -> Ptr e -> Off e -> Count e -> m ()@@ -135,18 +135,18 @@ (MonadPrim s m, Prim e) => MBytes p s -> Off Word8 -> Ptr e -> Off Word8 -> Count e -> m () moveByteOffMBytesToPtr (MBytes src#) (Off (I# srcOff#)) (Ptr dstAddr#) (Off (I# dstOff#)) c = unsafeIOToPrim $- memmoveMutableByteArrayToAddr# src# srcOff# dstAddr# dstOff# (fromCount# c)+ memmoveMutableByteArrayToAddr# src# srcOff# dstAddr# dstOff# (unCountBytes# c) {-# INLINE moveByteOffMBytesToPtr #-} compareByteOffBytesToPtr :: Prim e => Bytes p -> Off Word8 -> Ptr e -> Off Word8 -> Count e -> Ordering compareByteOffBytesToPtr (Bytes b#) (Off (I# off1#)) (Ptr addr#) (Off (I# off2#)) c =- toOrdering# (memcmpByteArrayAddr# b# off1# addr# off2# (fromCount# c))+ toOrdering# (memcmpByteArrayAddr# b# off1# addr# off2# (unCountBytes# c)) {-# INLINE compareByteOffBytesToPtr #-} compareByteOffPtrToBytes :: Prim e => Ptr e -> Off Word8 -> Bytes p -> Off Word8 -> Count e -> Ordering compareByteOffPtrToBytes (Ptr addr#) (Off (I# off1#)) (Bytes b#) (Off (I# off2#)) c =- toOrdering# (memcmpAddrByteArray# addr# off1# b# off2# (fromCount# c))+ toOrdering# (memcmpAddrByteArray# addr# off1# b# off2# (unCountBytes# c)) {-# INLINE compareByteOffPtrToBytes #-}
+ src/Data/Prim/Memory/Text.hs view
@@ -0,0 +1,54 @@+{-# LANGUAGE CPP #-}+{-# LANGUAGE DataKinds #-}+{-# LANGUAGE MagicHash #-}+-- |+-- Module : Data.Prim.Memory.Text+-- Copyright : (c) Alexey Kuleshevich 2020+-- License : BSD3+-- Maintainer : Alexey Kuleshevich <alexey@kuleshevi.ch>+-- Stability : experimental+-- Portability : non-portable+--+module Data.Prim.Memory.Text+ ( Text(..)+ , MText(..)+ , Array(..)+ , MArray(..)+ , toBytesArray+ , fromBytesArray+ , toMBytesMArray+ , fromMBytesMArray+ ) where++import Data.Text.Array+import Data.Text.Internal+import Data.Prim.Memory.Bytes.Internal+ ( Bytes(..)+ , MBytes(..)+ , Pinned(..)+ )++-- | Mutable version of a `Text`+data MText s =+ MText+ {-# UNPACK #-}!(MArray s) -- payload (Word16 elements)+ {-# UNPACK #-}!Int -- offset (units of Word16, not Char)+ {-# UNPACK #-}!Int -- length (units of Word16, not Char)++toBytesArray :: Array -> Bytes 'Inc+toBytesArray (Array ba#) = Bytes ba#+{-# INLINE toBytesArray #-}++fromBytesArray :: Bytes p -> Array+fromBytesArray (Bytes ba#) = Array ba#+{-# INLINE fromBytesArray #-}++toMBytesMArray :: MArray s -> MBytes 'Inc s+toMBytesMArray (MArray mba#) = MBytes mba#+{-# INLINE toMBytesMArray #-}++fromMBytesMArray :: MBytes p s -> MArray s+fromMBytesMArray (MBytes ba#) = MArray ba#+{-# INLINE fromMBytesMArray #-}++
+ tests/doctests.hs view
@@ -0,0 +1,6 @@+module Main where++import Test.DocTest (doctest)++main :: IO ()+main = doctest ["src", "-fobject-code"]