-- Hoogle documentation, generated by Haddock -- See Hoogle, http://www.haskell.org/hoogle/ -- | Unified interface for memory managemenet. -- -- Please see the README on GitHub at -- https://github.com/lehins/primal#readme @package primal-memory @version 0.1.0.0 module Data.Prim.Memory.Ptr copyPtrToMBytes :: (MonadPrim s m, Prim e) => Ptr e -> Off e -> MBytes p s -> Off e -> Count e -> m () movePtrToMBytes :: (MonadPrim s m, Prim e) => Ptr e -> Off e -> MBytes p s -> Off e -> Count e -> m () copyBytesToPtr :: (MonadPrim s m, Prim e) => Bytes p -> Off e -> Ptr e -> Off e -> Count e -> m () copyMBytesToPtr :: (MonadPrim s m, Prim e) => MBytes p s -> Off e -> Ptr e -> Off e -> Count e -> m () moveMBytesToPtr :: (MonadPrim s m, Prim e) => MBytes p s -> Off e -> Ptr e -> Off e -> Count e -> m () copyByteOffPtrToMBytes :: (MonadPrim s m, Prim e) => Ptr e -> Off Word8 -> MBytes p s -> Off Word8 -> Count e -> m () moveByteOffPtrToMBytes :: (MonadPrim s m, Prim e) => Ptr e -> Off Word8 -> MBytes p s -> Off Word8 -> Count e -> m () copyByteOffBytesToPtr :: (MonadPrim s m, Prim e) => Bytes p -> Off Word8 -> Ptr e -> Off Word8 -> Count e -> m () copyByteOffMBytesToPtr :: (MonadPrim s m, Prim e) => MBytes p s -> Off Word8 -> Ptr e -> Off Word8 -> Count e -> m () moveByteOffMBytesToPtr :: (MonadPrim s m, Prim e) => MBytes p s -> Off Word8 -> Ptr e -> Off Word8 -> Count e -> m () compareByteOffBytesToPtr :: Prim e => Bytes p -> Off Word8 -> Ptr e -> Off Word8 -> Count e -> Ordering compareByteOffPtrToBytes :: Prim e => Ptr e -> Off Word8 -> Bytes p -> Off Word8 -> Count e -> Ordering module Data.Prim.Memory.ByteString -- | Mutable version of a ByteString newtype MByteString s MByteString :: ByteString -> MByteString s -- | Builders denote sequences of bytes. They are Monoids -- where mempty is the zero-length sequence and mappend is -- concatenation, which runs in O(1). data Builder -- | Convert Bytes into a bytestring Builder toBuilderBytes :: Bytes p -> Builder -- | O(n) - Allocate Bytes and fill them using the supplied -- Builder fromBuilderBytes :: Builder -> Bytes 'Pin -- | A space-efficient representation of a Word8 vector, supporting -- many efficient operations. -- -- A ByteString contains 8-bit bytes, or by using the operations -- from Data.ByteString.Char8 it can be interpreted as containing -- 8-bit characters. data ByteString PS :: {-# UNPACK #-} !ForeignPtr Word8 -> {-# UNPACK #-} !Int -> {-# UNPACK #-} !Int -> ByteString -- | O(1) - Cast an immutable Bytes to an immutable -- ByteString toByteStringBytes :: Bytes 'Pin -> ByteString -- | O(n) - Allocate Bytes and fill them with the contents of -- a strict ByteString fromByteStringBytes :: Typeable p => ByteString -> Bytes p -- | O(n) - Allocate Bytes and fill them with the contents of -- a lazy ByteString fromLazyByteStringBytes :: ByteString -> Bytes 'Pin withPtrByteString :: MonadPrim s m => ByteString -> (Ptr a -> m b) -> m b withNoHaltPtrByteString :: MonadUnliftPrim s m => ByteString -> (Ptr a -> m b) -> m b -- | A compact representation of a Word8 vector. -- -- It has a lower memory overhead than a ByteString and and does -- not contribute to heap fragmentation. It can be converted to or from a -- ByteString (at the cost of copying the string data). It -- supports very few other operations. -- -- It is suitable for use as an internal representation for code that -- needs to keep many short strings in memory, but it should not -- be used as an interchange type. That is, it should not generally be -- used in public APIs. The ByteString type is usually more -- suitable for use in interfaces; it is more flexible and it supports a -- wide range of operations. data ShortByteString SBS :: ByteArray# -> ShortByteString -- | O(1) - Cast an immutable Bytes to an immutable -- ShortByteString toShortByteStringBytes :: Bytes p -> ShortByteString -- | O(1) - Cast an immutable ShortByteString to an immutable -- Bytes fromShortByteStringBytes :: ShortByteString -> Bytes 'Inc byteStringConvertError :: String -> a module Data.Prim.Memory.ForeignPtr -- | For memory allocated as pinned it is possible to operate on it with a -- Ptr. Any data type that is backed by such memory can have a -- PtrAccess instance. The simplest way is to convert it to a -- ForeignPtr and other functions will come for free. class PtrAccess s p -- | Convert to ForeignPtr. toForeignPtr :: (PtrAccess s p, MonadPrim s m) => p -> m (ForeignPtr a) -- | Apply an action to the raw memory Ptr to which the data type -- point to. Type of data stored in memory is left ambiguous -- intentionaly, so that the user can choose how to treat the memory -- content. withPtrAccess :: (PtrAccess s p, MonadPrim s m) => p -> (Ptr a -> m b) -> m b -- | See this GHC issue #18061 and related to get more insight why -- this is needed. withNoHaltPtrAccess :: (PtrAccess s p, MonadUnliftPrim s m) => p -> (Ptr a -> m b) -> m b -- | The type ForeignPtr represents references to objects that are -- maintained in a foreign language, i.e., that are not part of the data -- structures usually managed by the Haskell storage manager. The -- essential difference between ForeignPtrs and vanilla memory -- references of type Ptr a is that the former may be associated -- with finalizers. A finalizer is a routine that is invoked when -- the Haskell storage manager detects that - within the Haskell heap and -- stack - there are no more references left that are pointing to the -- ForeignPtr. Typically, the finalizer will, then, invoke -- routines in the foreign language that free the resources bound by the -- foreign object. -- -- The ForeignPtr is parameterised in the same way as Ptr. -- The type argument of ForeignPtr should normally be an instance -- of class Storable. data ForeignPtr a ForeignPtr :: Addr# -> ForeignPtrContents -> ForeignPtr a -- | This function casts a ForeignPtr parameterised by one type into -- another type. castForeignPtr :: () => ForeignPtr a -> ForeignPtr b -- | This function extracts the pointer component of a foreign pointer. -- This is a potentially dangerous operations, as if the argument to -- unsafeForeignPtrToPtr is the last usage occurrence of the given -- foreign pointer, then its finalizer(s) will be run, which potentially -- invalidates the plain pointer just obtained. Hence, -- touchForeignPtr must be used wherever it has to be guaranteed -- that the pointer lives on - i.e., has another usage occurrence. -- -- To avoid subtle coding errors, hand written marshalling code should -- preferably use withForeignPtr rather than combinations of -- unsafeForeignPtrToPtr and touchForeignPtr. However, the -- latter routines are occasionally preferred in tool generated -- marshalling code. unsafeForeignPtrToPtr :: () => ForeignPtr a -> Ptr a data ForeignPtrContents PlainForeignPtr :: !IORef Finalizers -> ForeignPtrContents MallocPtr :: MutableByteArray# RealWorld -> !IORef Finalizers -> ForeignPtrContents PlainPtr :: MutableByteArray# RealWorld -> ForeignPtrContents -- | Advances the given address by the given offset in number of elemeents. -- This operation does not affect associated finalizers in any way. plusOffForeignPtr :: Prim e => ForeignPtr e -> Off e -> ForeignPtr e -- | Advances the given address by the given offset in bytes. This -- operation does not affect associated finalizers in any way. plusByteOffForeignPtr :: ForeignPtr e -> Off Word8 -> ForeignPtr e -- | Find the offset in number of elements that is between the two pointers -- by subtracting one address from another and dividing the result by the -- size of an element. minusOffForeignPtr :: Prim e => ForeignPtr e -> ForeignPtr e -> Off e -- | Same as minusOffForeignPtr, but will also return the remainder -- in bytes that is left over. minusOffRemForeignPtr :: Prim e => ForeignPtr e -> ForeignPtr e -> (Off e, Off Word8) -- | Find the offset in bytes that is between the two pointers by -- subtracting one address from another. minusByteOffForeignPtr :: ForeignPtr e -> ForeignPtr e -> Off Word8 -- | Apply an action to the raw pointer. It is unsafe to return the actual -- pointer back from the action because memory itself might get garbage -- collected or cleaned up by finalizers. -- -- It is also important not to run non-terminating actions, because GHC -- can optimize away the logic that runs after the action and GC will -- happen before the action get's a chance to finish resulting in corrupt -- memory. Whenever you have an action that runs an infinite loop or ends -- in an exception throwing, make sure to use withNoHaltForeignPtr -- instead. withForeignPtr :: MonadPrim s m => ForeignPtr e -> (Ptr e -> m b) -> m b -- | Same thing as withForeignPtr except it should be used for never -- ending actions. See withNoHaltPtrAccess for more information on -- how this differes from withForeignPtr. withNoHaltForeignPtr :: MonadUnliftPrim s m => ForeignPtr e -> (Ptr e -> m b) -> m b -- | Similar to mallocPlainForeignPtr, except instead of -- Storable we use Prim and we are not restricted to -- IO, since finalizers are not possible with PlaintPtr mallocPlainForeignPtr :: forall e m s. (MonadPrim s m, Prim e) => m (ForeignPtr e) -- | Similar to mallocPlainForeignPtrArray, except instead of -- Storable we use Prim. mallocCountPlainForeignPtr :: (MonadPrim s m, Prim e) => Count e -> m (ForeignPtr e) -- | Just like mallocCountForeignPtr, but memory is also aligned -- according to Prim instance mallocCountPlainForeignPtrAligned :: forall e m s. (MonadPrim s m, Prim e) => Count e -> m (ForeignPtr e) -- | Lifted version of mallocForeignPtrBytes. mallocByteCountPlainForeignPtr :: MonadPrim s m => Count Word8 -> m (ForeignPtr e) -- | Lifted version of mallocForeignPtrAlignedBytes. mallocByteCountPlainForeignPtrAligned :: MonadPrim s m => Count Word8 -> Int -> m (ForeignPtr e) -- | Lifted version of finalizeForeignPtr. finalizeForeignPtr :: MonadPrim RW m => ForeignPtr e -> m () -- | A finalizer is represented as a pointer to a foreign function that, at -- finalisation time, gets as an argument a plain pointer variant of the -- foreign pointer that the finalizer is associated with. -- -- Note that the foreign function must use the ccall -- calling convention. type FinalizerPtr a = FunPtr Ptr a -> IO () -- | Lifted version of newForeignPtr. newForeignPtr :: MonadPrim RW m => FinalizerPtr e -> Ptr e -> m (ForeignPtr e) -- | Lifted version of newForeignPtr_. newForeignPtr_ :: MonadPrim RW m => Ptr e -> m (ForeignPtr e) -- | Lifted version of touchForeignPtr. touchForeignPtr :: MonadPrim s m => ForeignPtr e -> m () -- | Simila to mallocForeignPtr, except it operates on Prim, -- instead of Storable. mallocForeignPtr :: forall e m. (MonadPrim RW m, Prim e) => m (ForeignPtr e) -- | Similar to mallocForeignPtrArray, except instead of -- Storable we use Prim. mallocCountForeignPtr :: (MonadPrim RW m, Prim e) => Count e -> m (ForeignPtr e) -- | Just like mallocCountForeignPtr, but memory is also aligned -- according to Prim instance mallocCountForeignPtrAligned :: (MonadPrim RW m, Prim e) => Count e -> m (ForeignPtr e) -- | Lifted version of mallocForeignPtrBytes. mallocByteCountForeignPtr :: MonadPrim RW m => Count Word8 -> m (ForeignPtr e) -- | Lifted version of mallocForeignPtrAlignedBytes. mallocByteCountForeignPtrAligned :: MonadPrim RW m => Count Word8 -> Int -> m (ForeignPtr e) -- | Lifted version of addForeignPtrFinalizer addForeignPtrFinalizer :: MonadPrim RW m => FinalizerPtr e -> ForeignPtr e -> m () type FinalizerEnvPtr env a = FunPtr Ptr env -> Ptr a -> IO () -- | Lifted version of newForeignPtrEnv. newForeignPtrEnv :: MonadPrim RW m => FinalizerEnvPtr env e -> Ptr env -> Ptr e -> m (ForeignPtr e) -- | Lifted version of addForeignPtrFinalizerEnv addForeignPtrFinalizerEnv :: MonadPrim RW m => FinalizerEnvPtr env e -> Ptr env -> ForeignPtr e -> m () -- | Unlifted version of newConcForeignPtr newConcForeignPtr :: MonadUnliftPrim RW m => Ptr e -> m () -> m (ForeignPtr e) -- | Unlifted version of addForeignPtrConcFinalizer addForeignPtrConcFinalizer :: MonadUnliftPrim RW m => ForeignPtr a -> m () -> m () toForeignPtrBytes :: Bytes 'Pin -> ForeignPtr e toForeignPtrMBytes :: MBytes 'Pin s -> ForeignPtr e instance Data.Prim.Memory.ForeignPtr.PtrAccess s (GHC.ForeignPtr.ForeignPtr a) instance Data.Prim.Memory.ForeignPtr.PtrAccess s Data.ByteString.Internal.ByteString instance Data.Prim.Memory.ForeignPtr.PtrAccess s (Data.Prim.Memory.ByteString.MByteString s) instance Data.Prim.Memory.ForeignPtr.PtrAccess s (Data.Prim.Memory.Bytes.Internal.Bytes 'Data.Prim.Memory.Bytes.Internal.Pin) instance Data.Prim.Memory.ForeignPtr.PtrAccess s (Data.Prim.Memory.Bytes.Internal.MBytes 'Data.Prim.Memory.Bytes.Internal.Pin s) module Data.Prim.Memory.Internal -- | 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 -- fromByteArray# and unwrapper 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. data Bytes (p :: Pinned) Bytes :: ByteArray# -> Bytes -- | Mutable 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 -- fromMutableByteArray# and unwrapper toMutableByteArray# -- should be used instead. As a backdoor, of course, the actual -- constructor is available in Data.Prim.Memory.Internal module -- and specially unsafe function castPinnedMBytes was crafted. data MBytes (p :: Pinned) s MBytes :: MutableByteArray# s -> MBytes s -- | In Haskell there is a distinction between pinned or unpinned memory. -- -- Pinned memory is such, 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. -- -- 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 that fact through -- out the "primal" universe there is a distinction between memory that -- is either Pinned or Inconclusive. -- -- It is possible to use one of toPinnedBytes or -- toPinnedMBytes to get a conclusive type. data Pinned Pin :: Pinned Inc :: Pinned data MMemView a s MMemView :: {-# UNPACK #-} !Off Word8 -> {-# UNPACK #-} !Count Word8 -> !a s -> MMemView a s [mmvOffset] :: MMemView a s -> {-# UNPACK #-} !Off Word8 [mmvCount] :: MMemView a s -> {-# UNPACK #-} !Count Word8 [mmvMem] :: MMemView a s -> !a s data MemView a MemView :: {-# UNPACK #-} !Off Word8 -> {-# UNPACK #-} !Count Word8 -> !a -> MemView a [mvOffset] :: MemView a -> {-# UNPACK #-} !Off Word8 [mvCount] :: MemView a -> {-# UNPACK #-} !Count Word8 [mvMem] :: MemView a -> !a -- | 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 :: a -> MemState a s [unMemState] :: MemState a s -> a class MemWrite w readOffMem :: (MemWrite w, MonadPrim s m, Prim e) => w s -> Off e -> m e readByteOffMem :: (MemWrite w, MonadPrim s m, Prim e) => w s -> Off Word8 -> m e writeOffMem :: (MemWrite w, MonadPrim s m, Prim e) => w s -> Off e -> e -> m () writeByteOffMem :: (MemWrite w, MonadPrim s m, Prim e) => w s -> Off Word8 -> e -> m () -- | Source and target can be overlapping memory chunks moveByteOffToMBytesMem :: (MemWrite w, 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 :: (MemWrite w, MonadPrim s m, Prim e) => w s -> Off Word8 -> Ptr e -> Off Word8 -> Count e -> m () copyByteOffMem :: (MemWrite w, MonadPrim s m, MemRead r, Prim e) => r -> Off Word8 -> w s -> Off Word8 -> Count e -> m () moveByteOffMem :: (MemWrite w, MonadPrim s m, MemWrite w', Prim e) => w' s -> Off Word8 -> w s -> Off Word8 -> Count e -> m () -- | Write the same value into each cell starting at an offset. setMem :: (MemWrite w, MonadPrim s m, Prim e) => w s -> Off e -> Count e -> e -> m () -- | Generalized memory allocation and pure/mutable state conversion. class (MemRead (FrozenMem a), MemWrite a) => MemAlloc a where { type family FrozenMem a = (fa :: Type) | fa -> a; } getByteCountMem :: (MemAlloc a, MonadPrim s m) => a s -> m (Count Word8) allocByteCountMem :: (MemAlloc a, MonadPrim s m) => Count Word8 -> m (a s) thawMem :: (MemAlloc a, MonadPrim s m) => FrozenMem a -> m (a s) freezeMem :: (MemAlloc a, MonadPrim s m) => a s -> m (FrozenMem a) resizeMem :: (MemAlloc a, MonadPrim s m, Prim e) => a s -> Count e -> m (a s) class MemRead r byteCountMem :: MemRead r => r -> Count Word8 indexOffMem :: (MemRead r, Prim e) => r -> Off e -> e indexByteOffMem :: (MemRead r, Prim e) => r -> Off Word8 -> e -- | Source and target can't refer to the same memory chunks copyByteOffToMBytesMem :: (MemRead r, 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 :: (MemRead r, MonadPrim s m, Prim e) => r -> Off Word8 -> Ptr e -> Off Word8 -> Count e -> m () compareByteOffToPtrMem :: (MemRead r, MonadPrim s m, Prim e) => r -> Off Word8 -> Ptr e -> Off Word8 -> Count e -> m Ordering compareByteOffToBytesMem :: (MemRead r, MonadPrim s m, Prim e) => r -> Off Word8 -> Bytes p -> Off Word8 -> Count e -> m Ordering compareByteOffMem :: (MemRead r, MemRead r', Prim e) => r' -> Off Word8 -> r -> Off Word8 -> Count e -> Ordering modifyFetchOldMem :: (MemWrite w, MonadPrim s m, Prim b) => w s -> Off b -> (b -> b) -> m b modifyFetchNewMem :: (MemWrite w, MonadPrim s m, Prim b) => w s -> Off b -> (b -> b) -> m b modifyFetchOldMemM :: (MemWrite w, MonadPrim s m, Prim b) => w s -> Off b -> (b -> m b) -> m b modifyFetchNewMemM :: (MemWrite w, MonadPrim s m, Prim b) => w s -> Off b -> (b -> m b) -> m b defaultResizeMem :: (Prim e, MemAlloc a, MonadPrim s m) => a s -> Count e -> m (a s) -- | Make n copies of supplied region of memory into a contiguous -- chunk of memory. cycleMemN :: (MemAlloc a, MemRead r) => Int -> r -> FrozenMem a -- | Chunk of empty memory. emptyMem :: MemAlloc a => FrozenMem a -- | A region of memory that hold a single element. singletonMem :: forall e a. (MemAlloc a, Prim e) => e -> FrozenMem a -- | Allocate enough memory for number of elements. Memory is not -- initialized and may contain garbage. Use allocZeroMem if clean -- memory is needed. -- --
-- >>> 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] --convertMem :: (MemRead r, MemAlloc a) => r -> FrozenMem a -- | 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. -- --
-- >>> 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}
--
countMem :: forall e r. (MemRead r, Prim e) => r -> Count e
-- | Compute how many elements and a byte size remainder that can fit into
-- the region of memory.
--
--
-- >>> 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)
--
countRemMem :: forall e r. (MemRead r, Prim e) => r -> (Count e, Count Word8)
getCountMem :: (MemAlloc r, MonadPrim s m, Prim e) => r s -> m (Count e)
getCountRemMem :: (MemAlloc r, MonadPrim s m, Prim e) => r s -> m (Count e, Count Word8)
clone :: (MemAlloc r, MonadPrim s m) => r s -> m (r s)
eqMem :: (MemRead r1, MemRead r2) => r1 -> r2 -> Bool
-- | 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 -> Off e -> r2 -> Off e -> Count e -> Ordering
-- | 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]
-- | 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
--
-- -- >>> 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]) --toListSlackMem :: forall e r. (MemRead r, Prim e) => r -> ([e], [Word8]) -- | 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 loadListMemN :: (MemWrite r, MonadPrim s m, Prim e) => Count e -> Count Word8 -> [e] -> r s -> m Ordering loadListMemN_ :: (MemWrite r, MonadPrim s m, Prim e) => Count e -> [e] -> r s -> m () -- | 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_ :: (MonadPrim s m, MemAlloc r, Prim e) => [e] -> r s -> m () fromListMemN :: (MemAlloc a, Prim e) => Count e -> [e] -> (Ordering, FrozenMem a) fromListMemN_ :: (MemAlloc a, Prim e) => Count e -> [e] -> FrozenMem a fromListMem :: (MemAlloc a, Prim e) => [e] -> FrozenMem a -- | Load a list of bytes into a newly allocated memory region. Equivalent -- to pack for ByteString -- --
-- >>> fromByteListMem [0..10] :: Bytes 'Pin -- [0x00,0x01,0x02,0x03,0x04,0x05,0x06,0x07,0x08,0x09,0x0a] --fromByteListMem :: MemAlloc a => [Word8] -> FrozenMem a -- | Convert a memory region to a list of bytes. Equivalent to -- unpack for ByteString -- --
-- >>> toByteListMem (fromByteListMem [0..10] :: Bytes 'Pin) -- [0,1,2,3,4,5,6,7,8,9,10] --toByteListMem :: MemAlloc a => FrozenMem a -> [Word8] mapByteMem :: (MemRead r, MemAlloc a, Prim e) => (Word8 -> e) -> r -> FrozenMem a -- | 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] --mapByteOffMem :: (MemRead r, MemAlloc a, Prim e) => (Off Word8 -> Word8 -> e) -> r -> FrozenMem a mapByteMemM :: (MemRead r, MemAlloc a, MonadPrim s m, Prim e) => (Word8 -> m e) -> r -> m (FrozenMem a) mapByteOffMemM :: (MemRead r, MemAlloc a, MonadPrim s m, Prim e) => (Off Word8 -> Word8 -> m e) -> r -> m (FrozenMem a) -- | 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) loopShortM :: Monad m => Int -> (Int -> a -> Bool) -> (Int -> Int) -> a -> (Int -> a -> m a) -> m a loopShortM' :: Monad m => Int -> (Int -> a -> m Bool) -> (Int -> Int) -> a -> (Int -> a -> m a) -> m a 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) 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 () -- | 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] -- | 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 instance Data.Prim.Memory.Internal.MemWrite (Data.Prim.Memory.Internal.MemState (GHC.ForeignPtr.ForeignPtr a)) instance Data.Prim.Memory.Internal.MemAlloc Data.Prim.Memory.ByteString.MByteString instance Data.Typeable.Internal.Typeable p => Data.Prim.Memory.Internal.MemAlloc (Data.Prim.Memory.Bytes.Internal.MBytes p) instance Data.Prim.Memory.Internal.MemWrite Data.Prim.Memory.ByteString.MByteString instance Data.Prim.Memory.Internal.MemWrite (Data.Prim.Memory.Bytes.Internal.MBytes p) instance Data.Prim.Memory.Internal.MemRead Data.ByteString.Internal.ByteString instance Data.Prim.Memory.Internal.MemRead Data.ByteString.Short.Internal.ShortByteString instance Data.Prim.Memory.Internal.MemRead (Data.Prim.Memory.Bytes.Internal.Bytes p) instance GHC.Show.Show (Data.Prim.Memory.Bytes.Internal.Bytes p) instance Data.Typeable.Internal.Typeable p => GHC.Exts.IsList (Data.Prim.Memory.Bytes.Internal.Bytes p) instance GHC.Classes.Eq (Data.Prim.Memory.Bytes.Internal.Bytes p) instance GHC.Classes.Ord (Data.Prim.Memory.Bytes.Internal.Bytes p) instance Data.Typeable.Internal.Typeable p => GHC.Base.Semigroup (Data.Prim.Memory.Bytes.Internal.Bytes p) instance Data.Typeable.Internal.Typeable p => GHC.Base.Monoid (Data.Prim.Memory.Bytes.Internal.Bytes p) module Data.Prim.Memory.Bytes -- | 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 -- fromByteArray# and unwrapper 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. data Bytes (p :: Pinned) -- | Wrap ByteArray# into Bytes toByteArray# :: Bytes p -> ByteArray# -- | Unwrap Bytes to get the underlying ByteArray#. fromByteArray# :: ByteArray# -> Bytes 'Inc cloneBytes :: Typeable p => Bytes p -> Bytes p emptyBytes :: Bytes p eqBytes :: Bytes p1 -> Bytes p2 -> Bool singletonBytes :: forall e p. (Prim e, Typeable p) => e -> Bytes p isEmptyBytes :: Bytes p -> Bool -- | Allocated memory is not cleared, so make sure to fill it in properly, -- otherwise you might find some garbage there. createBytes :: forall p e b s m. (Prim e, Typeable p, MonadPrim s m) => Count e -> (MBytes p s -> m b) -> m (b, Bytes p) createBytes_ :: forall p e b s m. (Prim e, Typeable p, MonadPrim s m) => Count e -> (MBytes p s -> m b) -> m (Bytes p) createBytesST :: forall p e b. (Prim e, Typeable p) => Count e -> (forall s. MBytes p s -> ST s b) -> (b, Bytes p) createBytesST_ :: forall p e b. (Prim e, Typeable p) => Count e -> (forall s. MBytes p s -> ST s b) -> Bytes p -- | In Haskell there is a distinction between pinned or unpinned memory. -- -- Pinned memory is such, 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. -- -- 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 that fact through -- out the "primal" universe there is a distinction between memory that -- is either Pinned or Inconclusive. -- -- It is possible to use one of toPinnedBytes or -- toPinnedMBytes to get a conclusive type. data Pinned Pin :: Pinned Inc :: Pinned isPinnedBytes :: Bytes p -> Bool isPinnedMBytes :: MBytes p d -> Bool toPinnedBytes :: Bytes p -> Maybe (Bytes 'Pin) toPinnedMBytes :: MBytes p s -> Maybe (MBytes 'Pin s) relaxPinnedBytes :: Bytes p -> Bytes 'Inc relaxPinnedMBytes :: MBytes p e -> MBytes 'Inc e ensurePinnedBytes :: Bytes p -> Bytes 'Pin ensurePinnedMBytes :: MonadPrim s m => MBytes p s -> m (MBytes 'Pin s) -- | Mutable 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 -- fromMutableByteArray# and unwrapper toMutableByteArray# -- should be used instead. As a backdoor, of course, the actual -- constructor is available in Data.Prim.Memory.Internal module -- and specially unsafe function castPinnedMBytes was crafted. data MBytes (p :: Pinned) s -- | Wrap MutableByteArray# into MBytes toMutableByteArray# :: MBytes p s -> MutableByteArray# s -- | Unwrap MBytes to get the underlying MutableByteArray#. fromMutableByteArray# :: MutableByteArray# s -> MBytes 'Inc s -- | Check if two byte arrays refer to pinned memory and compare their -- pointers. isSameBytes :: Bytes p1 -> Bytes p2 -> Bool -- | Perform pointer equality on pinned Bytes. isSamePinnedBytes :: Bytes 'Pin -> Bytes 'Pin -> Bool -- | Check if two mutable bytes pointers refer to the same memory isSameMBytes :: MBytes p1 s -> MBytes p2 s -> Bool indexOffBytes :: Prim e => Bytes p -> Off e -> e indexByteOffBytes :: Prim e => Bytes p -> Off Word8 -> e byteCountBytes :: Bytes p -> Count Word8 -- | 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 -- | Get the count of elements of type a that can fit into bytes -- as well as the slack number of bytes that would be leftover in case -- when total number of bytes available is not exactly divisable by the -- size of the element that will be stored in the memory chunk. countRemBytes :: forall e p. Prim e => Bytes p -> (Count e, Count Word8) compareBytes :: Prim e => Bytes p1 -> Off e -> Bytes p2 -> Off e -> Count e -> Ordering compareByteOffBytes :: Prim e => Bytes p1 -> Off Word8 -> Bytes p2 -> Off Word8 -> Count e -> Ordering thawBytes :: MonadPrim s m => Bytes p -> m (MBytes p s) freezeMBytes :: MonadPrim s m => MBytes p s -> m (Bytes p) allocMBytes :: forall p e s m. (Typeable p, Prim e, MonadPrim s m) => Count e -> m (MBytes p s) singletonMBytes :: forall e p m s. (Prim e, Typeable p, MonadPrim s m) => e -> m (MBytes p s) allocPinnedMBytes :: (MonadPrim s m, Prim e) => Count e -> m (MBytes 'Pin s) allocAlignedMBytes :: forall e m s. (MonadPrim s m, Prim e) => Count e -> m (MBytes 'Pin s) allocUnpinnedMBytes :: (MonadPrim s m, Prim e) => Count e -> m (MBytes 'Inc s) callocMBytes :: (MonadPrim s m, Prim e, Typeable p) => Count e -> m (MBytes p s) callocAlignedMBytes :: (MonadPrim s m, Prim e) => Count e -> m (MBytes 'Pin s) -- | 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 () -- | Attempt to resize mutable bytes in place. -- --
-- >>> 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}
--
countMem :: forall e r. (MemRead r, Prim e) => r -> Count e
-- | Compute how many elements and a byte size remainder that can fit into
-- the region of memory.
--
--
-- >>> 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)
--
countRemMem :: forall e r. (MemRead r, Prim e) => r -> (Count e, Count Word8)
indexOffMem :: (MemRead r, Prim e) => r -> Off e -> e
eqMem :: (MemRead r1, MemRead r2) => r1 -> r2 -> Bool
-- | 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 -> Off e -> r2 -> Off e -> Count e -> Ordering
-- | Mutable 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
-- fromMutableByteArray# and unwrapper toMutableByteArray#
-- should be used instead. As a backdoor, of course, the actual
-- constructor is available in Data.Prim.Memory.Internal module
-- and specially unsafe function castPinnedMBytes was crafted.
data MBytes (p :: Pinned) s
-- | Generalized memory allocation and pure/mutable state conversion.
class (MemRead (FrozenMem a), MemWrite a) => MemAlloc a where {
type family FrozenMem a = (fa :: Type) | fa -> a;
}
class MemWrite w
getCountMem :: (MemAlloc r, MonadPrim s m, Prim e) => r s -> m (Count e)
getCountRemMem :: (MemAlloc r, MonadPrim s m, Prim e) => r s -> m (Count e, Count Word8)
readOffMem :: (MemWrite w, MonadPrim s m, Prim e) => w s -> Off e -> m e
writeOffMem :: (MemWrite w, MonadPrim s m, Prim e) => w s -> Off e -> e -> m ()
modifyFetchOldMem :: (MemWrite w, MonadPrim s m, Prim b) => w s -> Off b -> (b -> b) -> m b
modifyFetchOldMemM :: (MemWrite w, MonadPrim s m, Prim b) => w s -> Off b -> (b -> m b) -> m b
modifyFetchNewMem :: (MemWrite w, MonadPrim s m, Prim b) => w s -> Off b -> (b -> b) -> m b
modifyFetchNewMemM :: (MemWrite w, MonadPrim s m, Prim b) => w s -> Off b -> (b -> m b) -> m b
-- | Write the same value into each cell starting at an offset.
setMem :: (MemWrite w, MonadPrim s m, Prim e) => w s -> Off e -> Count e -> e -> m ()
copyMem :: (MonadPrim s m, MemRead r, MemWrite w, Prim e) => r -> Off e -> w s -> Off e -> Count e -> m ()
moveMem :: (MonadPrim s m, MemWrite w1, MemWrite w2, Prim e) => w1 s -> Off e -> w2 s -> Off e -> Count e -> m ()
-- | 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 :: a -> MemState a s
[unMemState] :: MemState a s -> a
-- | Allocate enough memory for number of elements. Memory is not
-- initialized and may contain garbage. Use allocZeroMem if clean
-- memory is needed.
--
-- -- >>> 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] --convertMem :: (MemRead r, MemAlloc a) => r -> FrozenMem a -- | 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] -- | 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 -- --
-- >>> 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]) --toListSlackMem :: forall e r. (MemRead r, Prim e) => r -> ([e], [Word8]) -- | Convert a memory region to a list of bytes. Equivalent to -- unpack for ByteString -- --
-- >>> toByteListMem (fromByteListMem [0..10] :: Bytes 'Pin) -- [0,1,2,3,4,5,6,7,8,9,10] --toByteListMem :: MemAlloc a => FrozenMem a -> [Word8] -- | Load a list of bytes into a newly allocated memory region. Equivalent -- to pack for ByteString -- --
-- >>> fromByteListMem [0..10] :: Bytes 'Pin -- [0x00,0x01,0x02,0x03,0x04,0x05,0x06,0x07,0x08,0x09,0x0a] --fromByteListMem :: MemAlloc a => [Word8] -> FrozenMem a fromListMem :: (MemAlloc a, Prim e) => [e] -> FrozenMem a fromListMemN :: (MemAlloc a, Prim e) => Count e -> [e] -> (Ordering, FrozenMem a) -- | 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_ :: (MonadPrim s m, MemAlloc r, Prim e) => [e] -> r s -> m () loadListMemN :: (MemWrite r, MonadPrim s m, Prim e) => Count e -> Count Word8 -> [e] -> r s -> m Ordering loadListMemN_ :: (MemWrite r, MonadPrim s m, Prim e) => Count e -> [e] -> r s -> m () -- | 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 module Data.Prim.Memory.ByteArray -- | An immutable array of bytes of type e newtype ByteArray (p :: Pinned) e ByteArray :: Bytes p -> ByteArray e -- | A mutable array of bytes of type e newtype MByteArray (p :: Pinned) e s MByteArray :: MBytes p s -> MByteArray e s -- | In Haskell there is a distinction between pinned or unpinned memory. -- -- Pinned memory is such, 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. -- -- 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 that fact through -- out the "primal" universe there is a distinction between memory that -- is either Pinned or Inconclusive. -- -- It is possible to use one of toPinnedBytes or -- toPinnedMBytes to get a conclusive type. data Pinned Pin :: Pinned Inc :: Pinned fromBytesByteArray :: Bytes p -> ByteArray p e toBytesByteArray :: ByteArray p e -> Bytes p castByteArray :: ByteArray p e' -> ByteArray p e fromMBytesMByteArray :: MBytes p s -> MByteArray p e s toMBytesMByteArray :: MByteArray p e s -> MBytes p s castMByteArray :: MByteArray p e' s -> MByteArray p e s allocMByteArray :: forall e p m s. (Typeable p, Prim e, MonadPrim s m) => Size -> m (MByteArray p e s) allocPinnedMByteArray :: forall e m s. (MonadPrim s m, Prim e) => Size -> m (MByteArray 'Pin e s) allocAlignedMByteArray :: (MonadPrim s m, Prim e) => Count e -> m (MByteArray 'Pin e s) allocUnpinnedMByteArray :: forall e m s. (MonadPrim s m, Prim e) => Size -> m (MByteArray 'Inc e s) -- | 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 () -- | Attempt to resize mutable bytes in place. -- --