Copyright | (c) Alexey Kuleshevich 2020 |
---|---|
License | BSD3 |
Maintainer | Alexey Kuleshevich <alexey@kuleshevi.ch> |
Stability | experimental |
Portability | non-portable |
Safe Haskell | None |
Language | Haskell2010 |
Synopsis
- module Data.Prim
- data Pinned
- data Bytes (p :: Pinned)
- class MemRead mr
- countMem :: forall e mr. (MemRead mr, Prim e) => mr -> Count e
- countRemMem :: forall e mr. (MemRead mr, Prim e) => mr -> (Count e, Count Word8)
- byteCountMem :: MemRead mr => mr -> Count Word8
- indexOffMem :: (MemRead mr, Prim e) => mr -> Off e -> e
- indexByteOffMem :: (MemRead mr, Prim e) => mr -> Off Word8 -> e
- emptyMem :: forall ma. MemAlloc ma => FrozenMem ma
- singletonMem :: forall e ma. (MemAlloc ma, Prim e) => e -> FrozenMem ma
- cycleMemN :: forall ma mr. (MemAlloc ma, MemRead mr) => Int -> mr -> FrozenMem ma
- createMemST :: forall e b ma. (MemAlloc ma, Prim e) => Count e -> (forall s. ma s -> ST s b) -> (b, FrozenMem ma)
- createMemST_ :: (MemAlloc ma, Prim e) => Count e -> (forall s. ma s -> ST s b) -> FrozenMem ma
- createZeroMemST :: forall e ma b. (MemAlloc ma, Prim e) => Count e -> (forall s. ma s -> ST s b) -> (b, FrozenMem ma)
- createZeroMemST_ :: forall e ma b. (MemAlloc ma, Prim e) => Count e -> (forall s. ma s -> ST s b) -> FrozenMem ma
- cloneMem :: forall ma. MemAlloc ma => FrozenMem ma -> FrozenMem ma
- copyMem :: (MonadPrim s m, MemRead mr, MemWrite mw, Prim e) => mr -> Off e -> mw s -> Off e -> Count e -> m ()
- copyByteOffMem :: (MemWrite mw, MonadPrim s m, MemRead mr, Prim e) => mr -> Off Word8 -> mw s -> Off Word8 -> Count e -> m ()
- copyByteOffToMBytesMem :: (MemRead mr, MonadPrim s m, Prim e) => mr -> Off Word8 -> MBytes p s -> Off Word8 -> Count e -> m ()
- copyByteOffToPtrMem :: (MemRead mr, MonadPrim s m, Prim e) => mr -> Off Word8 -> Ptr e -> Off Word8 -> Count e -> m ()
- eqMem :: forall e mr. (Prim e, Eq e, MemRead mr) => mr -> mr -> Bool
- eqOffMem :: (Prim e, Eq e, MemRead mr1, MemRead mr2) => mr1 -> Off e -> mr2 -> Off e -> Count e -> Bool
- eqByteMem :: (MemRead mr1, MemRead mr2) => mr1 -> mr2 -> Bool
- eqByteOffMem :: (MemRead mr1, MemRead mr2) => mr1 -> Off Word8 -> mr2 -> Off Word8 -> Count Word8 -> Bool
- compareMem :: forall e mr. (Prim e, Ord e, MemRead mr) => mr -> mr -> Ordering
- compareOffMem :: (Prim e, Ord e, MemRead mr1, MemRead mr2) => mr1 -> Off e -> mr2 -> Off e -> Count e -> Ordering
- compareByteMem :: (MemRead mr1, MemRead mr2) => mr1 -> mr2 -> Ordering
- compareByteOffMem :: (MemRead mr, MemRead mr', Prim e) => mr' -> Off Word8 -> mr -> Off Word8 -> Count e -> Ordering
- compareByteOffToPtrMem :: (MemRead mr, MonadPrim s m, Prim e) => mr -> Off Word8 -> Ptr e -> Off Word8 -> Count e -> m Ordering
- compareByteOffToBytesMem :: (MemRead mr, Prim e) => mr -> Off Word8 -> Bytes p -> Off Word8 -> Count e -> Ordering
- convertMem :: (MemRead mr, MemAlloc ma) => mr -> FrozenMem ma
- toListMem :: forall e mr. (MemRead mr, Prim e) => mr -> [e]
- toListSlackMem :: forall e mr. (MemRead mr, Prim e) => mr -> ([e], [Word8])
- toByteListMem :: forall ma. MemAlloc ma => FrozenMem ma -> [Word8]
- foldrCountMem :: forall e b mr. (MemRead mr, Prim e) => Count e -> (e -> b -> b) -> b -> mr -> b
- showsHexMem :: MemRead mr => mr -> [ShowS]
- fromListMem :: forall e ma. (Prim e, MemAlloc ma) => [e] -> FrozenMem ma
- fromByteListMem :: forall ma. MemAlloc ma => [Word8] -> FrozenMem ma
- fromListMemN :: forall e ma. (Prim e, MemAlloc ma) => Count e -> [e] -> (Either [e] (Count e), FrozenMem ma)
- fromListZeroMemN :: forall e ma. (Prim e, MemAlloc ma) => Count e -> [e] -> (Either [e] (Count e), FrozenMem ma)
- fromListZeroMemN_ :: forall e ma. (Prim e, MemAlloc ma) => Count e -> [e] -> FrozenMem ma
- data MBytes (p :: Pinned) s
- class MemWrite mw
- class (MemRead (FrozenMem ma), MemWrite ma) => MemAlloc ma where
- newtype MemState a s = MemState {
- unMemState :: a
- getCountMutMem :: forall e ma m s. (MemAlloc ma, MonadPrim s m, Prim e) => ma s -> m (Count e)
- getCountRemMutMem :: forall e ma m s. (MemAlloc ma, MonadPrim s m, Prim e) => ma s -> m (Count e, Count Word8)
- getByteCountMutMem :: (MemAlloc ma, MonadPrim s m) => ma s -> m (Count Word8)
- readOffMutMem :: (MemWrite mw, MonadPrim s m, Prim e) => mw s -> Off e -> m e
- readByteOffMutMem :: (MemWrite mw, MonadPrim s m, Prim e) => mw s -> Off Word8 -> m e
- writeOffMutMem :: (MemWrite mw, MonadPrim s m, Prim e) => mw s -> Off e -> e -> m ()
- writeByteOffMutMem :: (MemWrite mw, MonadPrim s m, Prim e) => mw s -> Off Word8 -> e -> m ()
- setMutMem :: (MemWrite mw, MonadPrim s m, Prim e) => mw s -> Off e -> Count e -> e -> m ()
- modifyFetchOldMutMem :: (MemWrite mw, MonadPrim s m, Prim e) => mw s -> Off e -> (e -> e) -> m e
- modifyFetchOldMutMemM :: (MemWrite mw, MonadPrim s m, Prim e) => mw s -> Off e -> (e -> m e) -> m e
- modifyFetchNewMutMem :: (MemWrite mw, MonadPrim s m, Prim e) => mw s -> Off e -> (e -> e) -> m e
- modifyFetchNewMutMemM :: (MemWrite mw, MonadPrim s m, Prim e) => mw s -> Off e -> (e -> m e) -> m e
- allocMutMem :: (MemAlloc ma, Prim e, MonadPrim s m) => Count e -> m (ma s)
- allocZeroMutMem :: forall e ma m s. (MemAlloc ma, MonadPrim s m, Prim e) => Count e -> m (ma s)
- reallocMutMem :: (MemAlloc ma, MonadPrim s m, Prim e) => ma s -> Count e -> m (ma s)
- withScrubbedMutMem :: forall e ma m a. (MonadUnliftPrim RW m, Prim e, MemAlloc ma, PtrAccess RW (ma RW)) => Count e -> (ma RW -> m a) -> m a
- defaultReallocMutMem :: (Prim e, MemAlloc ma, MonadPrim s m) => ma s -> Count e -> m (ma s)
- thawCloneMem :: forall ma m s. (MemAlloc ma, MonadPrim s m) => FrozenMem ma -> m (ma s)
- thawCopyMem :: forall e ma m s. (Prim e, MemAlloc ma, MonadPrim s m) => FrozenMem ma -> Off e -> Count e -> m (ma s)
- thawMem :: (MemAlloc ma, MonadPrim s m) => FrozenMem ma -> m (ma s)
- freezeCloneMutMem :: forall ma m s. (MemAlloc ma, MonadPrim s m) => ma s -> m (FrozenMem ma)
- freezeCopyMutMem :: forall e ma m s. (Prim e, MemAlloc ma, MonadPrim s m) => ma s -> Off e -> Count e -> m (FrozenMem ma)
- freezeMutMem :: (MemAlloc ma, MonadPrim s m) => ma s -> m (FrozenMem ma)
- cloneMutMem :: forall ma m s. (MemAlloc ma, MonadPrim s m) => ma s -> m (ma s)
- moveMutMem :: (MonadPrim s m, MemWrite mw1, MemWrite mw2, Prim e) => mw1 s -> Off e -> mw2 s -> Off e -> Count e -> m ()
- moveByteOffMutMem :: (MemWrite mw, MonadPrim s m, MemWrite mw', Prim e) => mw' s -> Off Word8 -> mw s -> Off Word8 -> Count e -> m ()
- moveByteOffToMBytesMutMem :: (MemWrite mw, MonadPrim s m, Prim e) => mw s -> Off Word8 -> MBytes p s -> Off Word8 -> Count e -> m ()
- moveByteOffToPtrMutMem :: (MemWrite mw, MonadPrim s m, Prim e) => mw s -> Off Word8 -> Ptr e -> Off Word8 -> Count e -> m ()
- loadListMutMem :: forall e ma m s. (Prim e, MemAlloc ma, MonadPrim s m) => [e] -> ma s -> m ([e], Count e)
- loadListMutMem_ :: forall e ma m s. (Prim e, MemAlloc ma, MonadPrim s m) => [e] -> ma s -> m ()
- loadListMutMemN :: forall e mw m s. (MemWrite mw, MonadPrim s m, Prim e) => Count e -> [e] -> mw s -> m ([e], Count e)
- loadListMutMemN_ :: forall e mw m s. (Prim e, MemWrite mw, MonadPrim s m) => Count e -> [e] -> mw s -> m ()
- loadListOffMutMem :: forall e ma m s. (Prim e, MemAlloc ma, MonadPrim s m) => [e] -> ma s -> Off e -> m ([e], Count e)
- loadListOffMutMemN :: (MemWrite mw, MonadPrim s m, Prim e) => Count e -> [e] -> mw s -> Off e -> m ([e], Count e)
- loadListByteOffMutMem :: (MemAlloc ma, MonadPrim s m, Prim e) => [e] -> ma s -> Off Word8 -> m ([e], Count e)
- loadListByteOffMutMemN :: (MemWrite mw, MonadPrim s m, Prim e) => Count e -> [e] -> mw s -> Off Word8 -> m ([e], Count e)
Documentation
module Data.Prim
In GHC there is a distinction between pinned and unpinned memory.
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 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
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
or Pin
ned
.Inc
onclusive
It is possible to use one of toPinnedBytes
or
toPinnedMBytes
to get a conclusive type.
Since: 0.1.0
Immutable
data Bytes (p :: Pinned) Source #
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 from Data.Prim.Memory.Internal
Instances
Type class that can be implemented for an immutable data type that provides read-only direct access to memory
isSameMem, byteCountMem, indexByteOffMem, copyByteOffToMBytesMem, copyByteOffToPtrMem, compareByteOffToPtrMem, compareByteOffToBytesMem, compareByteOffMem
Instances
Size
countMem :: forall e mr. (MemRead mr, Prim e) => mr -> Count e Source #
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
>>>
let 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 b :: Count Word64
Count {unCount = 0}
Since: 0.1.0
countRemMem :: forall e mr. (MemRead mr, Prim e) => mr -> (Count e, Count Word8) Source #
Figure out how many elements and a byte size remainder can fit into the immutable region of memory.
Examples
>>>
let 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})>>>
countRemMem @Word64 b
(Count {unCount = 0},Count {unCount = 6})
Since: 0.1.0
byteCountMem :: MemRead mr => mr -> Count Word8 Source #
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
Index
:: (MemRead mr, Prim e) | |
=> mr | memRead - Memory to read an element from |
-> Off e | off - Offset in number of elements from the beginning of Preconditions: 0 <= off unOffBytes off <= unCount (byteCountMem memRead - byteCountType @e) |
-> e |
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
:: (MemRead mr, Prim e) | |
=> mr | memRead - Memory to read an element from |
-> Off Word8 | off - Offset in number of elements from the beginning of Preconditions: 0 <= unOff off unOff off <= unCount (byteCountMem memRead - byteCountType @e) |
-> e |
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
Construct
:: forall e ma. (MemAlloc ma, Prim e) | |
=> e | The single element that will be stored in the newly allocated region of memory |
-> FrozenMem ma |
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
cycleMemN :: forall ma mr. (MemAlloc ma, MemRead mr) => Int -> mr -> FrozenMem ma Source #
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
:: forall e b ma. (MemAlloc ma, Prim e) | |
=> Count e | memCount - Amount of memory to allocate for the region in number of elements of
type Preconditions: 0 <= memCount Possibility of overflow: memCount <= fromByteCount maxBound When converted to bytes the value should be less then available physical memory |
-> (forall s. ma s -> ST s b) | memFillAction - This action will be used to modify the contents of newly allocated memory. Make sure to overwrite all of it, otherwise it might lead to breaking referential transparency. |
-> (b, FrozenMem ma) |
Allocate a mutable region of memory and fill it with the supplied ST
action. Besides
the newly filled frozen memory this function also returns the result produced by the
filling action. See createMemST_
for the version that discards it. Also see
createZeroMemST
for a safer alternative.
- Unsafe
- Same caviats as in
allocMutMem
Since: 0.1.0
:: (MemAlloc ma, Prim e) | |
=> Count e | memCount - Amount of memory to allocate for the region in number of elements of
type Preconditions: 0 <= memCount Possibility of overflow: memCount <= fromByteCount maxBound When converted to bytes the value should be less then available physical memory |
-> (forall s. ma s -> ST s b) | memFillAction - This action will be used to modify the contents of newly allocated memory. Make sure to overwrite all of it, otherwise it might lead to breaking referential transparency. |
-> FrozenMem ma |
:: forall e ma b. (MemAlloc ma, Prim e) | |
=> Count e | memCount - Amount of memory to allocate for the region in number of elements of
type Preconditions: 0 <= memCount Possibility of overflow: memCount <= fromByteCount maxBound When converted to bytes the value should be less then available physical memory |
-> (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 the whole thing will be reset to zeros before applying this action. |
-> (b, FrozenMem ma) |
Same as createMemST
, except it in ensures that the memory is reset to zeros right
after allocation
- Unsafe
- Same caviats as in
allocZeroMutMem
: violation of precondition formemCount
may result in undefined behavior orHeapOverflow
async exception.
Since: 0.1.0
:: forall e ma b. (MemAlloc ma, Prim e) | |
=> Count e | memCount - Amount of memory to allocate for the region in number of elements of
type 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: memCount <= fromByteCount 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 the whole thing will be reset to zeros before applying this action. |
-> FrozenMem ma |
Same as createMemST_
, except it ensures that the memory gets reset with zeros right
after allocation and prior applying the ST
filling action fillAction
.
- Unsafe
- Same reasons as
allocZeroMutMem
: violation of precondition formemCount
may result in undefined behavior orHeapOverflow
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) -> writeByteOffMutMem m i b
>>>
toListMem bc :: String
"Haskell"
Since: 0.1.0
Copy
Copy all of the data from the source into a newly allocate memory region of identical size.
Examples
>>>
:set -XDataKinds
>>>
import Data.Prim.Memory
>>>
import Data.Prim.Memory.Bytes
>>>
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">>>
report (eqByteMem xs ys) (isSameBytes xs ys)
"Bytes equal: True, their pointers equal: False"
Since: 0.2.0
:: (MonadPrim s m, MemRead mr, MemWrite mw, Prim e) | |
=> mr | memSourceRead - Read-only source memory region from which the data will copied |
-> Off e | memSourceOff - Offset into source memory in number of elements of type 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 targetCount <- getCountMutMem memTargetWrite unOff memTargetOff < unCount targetCount |
-> Count e | memCount - Number of elements of type Preconditions: 0 <= memCount Both source and target memory regions must have enough memory to perform a copy
of unOff memSourceOff + unCount memCount < unCount (countMem memSourceRead) and for targetCount <- getCountMutMem memTargetWrite unOff memTargetOff + unCount memCount < unCount targetCount |
-> m () |
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 countmemCount
is violated a call to this function can result in: copy of data that doesn't belong tomemSourceRead
, heap corruption or failure with a segfault.
Since: 0.1.0
:: (MemWrite mw, 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 targetByteCount <- getByteCountMutMem memTargetWrite unOffBytes memTargetOff <= unCount (targetByteCount - byteCountType @e) |
-> Count e | memCount - Number of elements of type Preconditions: 0 <= memCount Both source and target memory regions must have enough memory to perform a copy
of unOff memSourceOff + unCountBytes memCount <= unCount (byteCountMem memSourceRead - byteCountType @e) and for targetByteCount <- getByteCountMutMem memTargetWrite unOff memTargetOff + unCountBytes memCount <= unCount (targetByteCount - 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 countmemCount
is violated a call to this function can result in: copy of data that doesn't belong tomemSourceRead
, heap corruption or failure with a segfault.
Since: 0.1.0
copyByteOffToMBytesMem Source #
:: (MemRead mr, 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 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
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 countmemCount
is violated the result is either unpredictable output or failure with a segfault.
Since: 0.1.0
:: (MemRead mr, 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 |
-> Off Word8 | memTargetOff - Number of bytes to advance the pointer Precondition: Once the pointer is advanced by |
-> Count e | memCount - Number of elements of type Preconditions: 0 <= memCount unCountBytes memCount + unOff memSourceOff <= unCount (byteCountMem memSourceRead - 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 countmemCount
is violated a call to this function can result in: copy of data that doesn't belong tomemSourceRead
, heap corruption or failure with a segfault.
Since: 0.1.0
Compare
:: (Prim e, Eq e, MemRead mr1, MemRead mr2) | |
=> mr1 | memRead1 - First region of memory |
-> Off e | memOff1 - Offset for Precondition: 0 <= memOff1 |
-> mr2 | memRead2 - Second region of memory |
-> Off e | memOff2 - Offset for Precondition: 0 <= memOff2 |
-> Count e | memCount - Number of elements of type Preconditions: 0 <= memCount offToCount memOff1 + memCount < countMem memRead1 offToCount memOff2 + memCount < countMem memRead2 |
-> Bool |
Check two regions of memory for equality using the Eq
instance. It will return
True
whenever both regions hold exactly the same elements and False
as soon as the
first pair of mismatched elements is discovered in the two regions. It is safe for both
regions to refer to the same part of memory.
- Unsafe
- When any precondition for either of the offsets
memOff1
,memOff2
or the element countmemCount
is violated the result is either unpredictable output or failure with a segfault.
Since: 0.3.0
eqByteMem :: (MemRead mr1, MemRead mr2) => mr1 -> mr2 -> Bool Source #
Compare two memory regions for equality byte-by-byte. False
is returned immediately
when sizes reported by byteCountMem
do not match.
Since: 0.3.0
:: (MemRead mr1, MemRead mr2) | |
=> mr1 | memRead1 - First region of memory |
-> Off Word8 | memOff1 - Offset for Precondition: 0 <= memOff1 |
-> mr2 | memRead2 - Second region of memory |
-> Off Word8 | memOff2 - Offset for Precondition: 0 <= memOff2 |
-> Count Word8 | memCount - Number of bytes compare Preconditions: 0 <= memCount offToCount memOff1 + memCount < countMem memRead1 offToCount memOff2 + memCount < countMem memRead2 |
-> Bool |
Compare two memory regions byte-by-byte. Computation may be short-circuited on the
first mismatch, but it is MemRead
implementation specific.
Since: 0.3.0
:: forall e mr. (Prim e, Ord e, MemRead mr) | |
=> mr | memRead1 - First region of memory |
-> mr | memRead2 - Second region of memory |
-> Ordering |
Compare two regions using the Ord
instance. It will return EQ
whenever both
regions hold exactly the same elements and LT
or GT
as soon as the first discovered
element 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: 0.3.0
:: (Prim e, Ord e, MemRead mr1, MemRead mr2) | |
=> mr1 | memRead1 - First region of memory |
-> Off e | memOff1 - Offset for Precondition: 0 <= memOff1 |
-> mr2 | memRead2 - Second region of memory |
-> Off e | memOff2 - Offset for Precondition: 0 <= memOff2 |
-> Count e | memCount - Number of elements of type Preconditions: 0 <= memCount offToCount memOff1 + memCount < countMem memRead1 offToCount memOff2 + memCount < countMem memRead2 |
-> Ordering |
Compare two regions using the Ord
instance. It will return EQ
whenever both
regions hold exactly the same elements and LT
or GT
as soon as the first discovered
element 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.
- Unsafe
- When any precondition for either of the offsets
memOff1
,memOff2
or the element countmemCount
is violated the result is either unpredictable output or failure with a segfault.
Since: 0.3.0
compareByteMem :: (MemRead mr1, MemRead mr2) => mr1 -> mr2 -> Ordering Source #
Compare two memory regions byte-by-byte.
Since: 0.3.0
:: (MemRead mr, MemRead mr', Prim e) | |
=> mr' | memRead1 - First memory region |
-> Off Word8 | memOff1 - Offset for Preconditions: 0 <= memOff1 unOff memOff1 <= unCount (byteCountMem memRead1 - byteCountType @e) |
-> mr | memRead2 - Second memory region |
-> Off Word8 | memOff2 - Offset for Preconditions: 0 <= memOff2 unOff memOff2 <= unCount (byteCountMem memRead2 - byteCountType @e) |
-> Count e | memCount - Number of elements of type 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 countmemCount
is violated the result is either unpredictable output or failure with a segfault.
Since: 0.1.0
compareByteOffToPtrMem Source #
:: (MemRead mr, MonadPrim s m, Prim e) | |
=> mr | memRead1 - First memory region |
-> Off Word8 | memOff1 - Offset for 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 |
-> Off Word8 | memOff2 - Number of bytes to advance the pointer Precondition: Once the pointer is advanced by |
-> Count e | memCount - Number of elements of type 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 a region addressed by a Ptr
inside of a MonadPrim
.
- Unsafe
- When any precondition for either of the offsets
memOff1
,memOff2
, the pointermemRead2
or the element countmemCount
is violated the result is either unpredictable output or failure with a segfault.
Since: 0.1.0
compareByteOffToBytesMem Source #
:: (MemRead mr, Prim e) | |
=> mr | memRead1 - First memory region |
-> Off Word8 | memOff1 - Offset for Preconditions: 0 <= memOff1 unOff memOff1 <= unCount (byteCountMem memRead1 - byteCountType @e) |
-> Bytes p | memRead2- Second memory region that is backed by |
-> Off Word8 | memOff2 - Offset for Preconditions: 0 <= memOff2 unOff memOff2 <= unCount (byteCountMem memRead2 - byteCountType @e) |
-> Count e | memCount - Number of elements of type Preconditions: 0 <= memCount unCountBytes memCount + unOff memOff1 <= unCount (byteCountMem memRead1 - byteCountType @e) unCountBytes memCount + unOff memOff2 <= unCount (byteCountMem memRead2 - byteCountType @e) |
-> 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 countmemCount
is violated the result is either unpredictable output or failure with a segfault.
Since: 0.1.0
Convert
convertMem :: (MemRead mr, MemAlloc ma) => mr -> FrozenMem ma Source #
O(n) - Convert a read-only memory region into a newly allocated other type of memory region
>>>
import Data.ByteString (pack)
>>>
let 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
To list
toListMem :: forall e mr. (MemRead mr, Prim e) => mr -> [e] Source #
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
toListSlackMem :: forall e mr. (MemRead mr, Prim e) => mr -> ([e], [Word8]) Source #
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
>>>
let 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
toByteListMem :: forall ma. MemAlloc ma => FrozenMem ma -> [Word8] Source #
Convert a memory region to a list of bytes. Equivalent to unpack
for ByteString
Example
>>>
toByteListMem (fromByteListMem [0..10] :: Bytes 'Pin)
[0,1,2,3,4,5,6,7,8,9,10]
Since: 0.1.0
foldrCountMem :: forall e b mr. (MemRead mr, Prim e) => Count e -> (e -> b -> b) -> b -> mr -> b Source #
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
showsHexMem :: MemRead mr => mr -> [ShowS] Source #
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
From list
fromListMem :: forall e ma. (Prim e, MemAlloc ma) => [e] -> FrozenMem ma Source #
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
fromByteListMem :: forall ma. MemAlloc ma => [Word8] -> FrozenMem ma Source #
Same as fromListMem
but restricted to a list of Word8
. Load a list of bytes into
a newly allocated memory region. Equivalent to pack
for
ByteString
Examples
>>>
fromByteListMem [0..10] :: Bytes 'Pin
[0x00,0x01,0x02,0x03,0x04,0x05,0x06,0x07,0x08,0x09,0x0a]
Since: 0.1.0
:: 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) |
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
:: 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) |
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 -> [e] -> FrozenMem ma Source #
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
Mutable
data MBytes (p :: Pinned) s Source #
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.
Instances
Type class that can be implemented for a mutable data type that provides direct read and write access to memory
isSameMutMem, readByteOffMutMem, writeByteOffMutMem, moveByteOffToMBytesMutMem, moveByteOffToPtrMutMem, copyByteOffMem, moveByteOffMutMem, setMutMem
Instances
class (MemRead (FrozenMem ma), MemWrite ma) => MemAlloc ma Source #
Generalized memory allocation and pure/mutable state conversion.
type FrozenMem ma = (fm :: Type) | fm -> ma Source #
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.
Instances
A wrapper that adds a phantom state token. It can be used with types that either
don't have such state token or are designed to work in IO
and therefore restricted
to RealWorld
. Using this wrapper is very much unsafe, so make sure you know what you are
doing.
MemState | |
|
Instances
Size
getCountMutMem :: forall e ma m s. (MemAlloc ma, MonadPrim s m, Prim e) => ma s -> m (Count e) Source #
Figure out how many elements fits into the mutable region of memory. Similar to
countMem
, except that it is not a pure funciton, since the size of mutable memory can
change throuhout its lifetime. It is possible that there is a remainder of bytes left,
see getCountRemMem
for getting that too.
Examples
>>>
mb <- thawMem (fromListMem [0 .. 5 :: Word8] :: Bytes 'Pin)
>>>
getCountMutMem mb :: IO (Count Word16)
Count {unCount = 3}>>>
getCountMutMem mb :: IO (Count Word32)
Count {unCount = 1}>>>
getCountMutMem mb :: IO (Count Word64)
Count {unCount = 0}>>>
mb' <- reallocMutMem mb (6 :: Count Word64)
>>>
getCountMutMem mb' :: IO (Count Word32)
Count {unCount = 12}
Since: 0.3.0
getCountRemMutMem :: forall e ma m s. (MemAlloc ma, MonadPrim s m, Prim e) => ma s -> m (Count e, Count Word8) Source #
Figure out how many elements and a byte size remainder can fit into the mutable
region of memory. Similar to countRemMem
, except it is a monadic action for mutable
regions instead of a pure function for immutable memory. See getCountMutMem
for getting
the element count only.
Examples
>>>
b <- thawMem (fromListMem [0 .. 5 :: Word8] :: Bytes 'Pin)
>>>
getCountRemMutMem @Word16 b
(Count {unCount = 3},Count {unCount = 0})>>>
getCountRemMutMem @Word32 b
(Count {unCount = 1},Count {unCount = 2})>>>
getCountRemMutMem @Word64 b
(Count {unCount = 0},Count {unCount = 6})
Since: 0.3.0
getByteCountMutMem :: (MemAlloc ma, MonadPrim s m) => ma s -> m (Count Word8) Source #
Extract the number of bytes a mutable memory region can hold, i.e. what is the
total allocated size for this region. The size of a region can be changes and in some
circuimstances even in place without copy, see reallocMutMem
for more info.
Examples
>>>
m <- allocMutMem (10 :: Count Int64) :: IO (MBytes 'Pin RW)
>>>
getByteCountMutMem m
Count {unCount = 80}
Since: 0.3.0
Read
:: (MemWrite mw, 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 Preconditions: 0 <= off With offset applied it should still refer to the same memory region. For types that
also implement count <- getByteCountMutMem memRead unOff (toByteOff off) <= unCount (count - byteCountType @e) |
-> m e |
Read an element with an offset in number of elements, rather than bytes as it is
the case with readByteOffMutMem
.
- 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.3.0
:: (MemWrite mw, 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 Preconditions: 0 <= off With offset applied it should still refer to the same memory region. For types that
also implement count <- getByteCountMutMem memRead unOff (toByteOff off) <= unCount (count - byteCountType @e) |
-> m e |
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.3.0
Write
:: (MemWrite mw, 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 Preconditions: 0 <= off With offset applied it should still refer to the same memory region. For types that
also implement count <- getByteCountMutMem memWrite unOff (toByteOff off) <= unCount (count - byteCountType @e) |
-> e | elt - Element to write |
-> m () |
Write an element with an offset in number of elements, rather than bytes as it is
the case with writeByteOffMutMem
.
- 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.3.0
:: (MemWrite mw, 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 Preconditions: 0 <= off With offset applied it should still refer to the same memory region. For types that
also implement count <- getByteCountMutMem memWrite unOff (toByteOff off) <= unCount (count - byteCountType @e) |
-> e | |
-> m () |
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.3.0
:: (MemWrite mw, 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 targetByteCount <- getByteCountMutMem memTarget unOffBytes memTargetOff <= unCount (targetByteCount - byteCountType @e) |
-> Count e | memCount - Number of times the element Preconditions: 0 <= memCount Target memory region should have enough memory to perform a set operation of the
supplied element targetByteCount <- getByteCountMutMem 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 |
-> 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.3.0
modifyFetchOldMutMem :: (MemWrite mw, MonadPrim s m, Prim e) => mw s -> Off e -> (e -> e) -> m e Source #
modifyFetchOldMutMemM :: (MemWrite mw, MonadPrim s m, Prim e) => mw s -> Off e -> (e -> m e) -> m e Source #
modifyFetchNewMutMem :: (MemWrite mw, MonadPrim s m, Prim e) => mw s -> Off e -> (e -> e) -> m e Source #
modifyFetchNewMutMemM :: (MemWrite mw, MonadPrim s m, Prim e) => mw s -> Off e -> (e -> m e) -> m e Source #
Allocate
:: (MemAlloc ma, Prim e, MonadPrim s m) | |
=> Count e | memCount - Amount of memory to allocate for the region in number of elements of
type Preconditions: 0 <= memCount Possibility of overflow: memCount <= fromByteCount maxBound When converted to bytes the value should be less then available physical memory |
-> m (ma s) |
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 allocZeroMutMem
,
unless it is guaranteed that all of allocated memory will be overwritten.
- Unsafe
- When any of preconditions for
memCount
argument is violated the outcome is unpredictable. One possible outcome is termination withHeapOverflow
async exception. In a pure setting, such as when executed withinrunST
, if allocated memory is not fully overwritten it can lead to violation of referential transparency, because contents of newly allocated region is non-determinstic.
Since: 0.3.0
:: forall e ma m s. (MemAlloc ma, MonadPrim s m, Prim e) | |
=> Count e | memCount - Amount of memory to allocate for the region in number of elements of
type Preconditions: 0 <= memCount Possibility of overflow: memCount <= fromByteCount maxBound When converted to bytes the value should be less then available physical memory |
-> m (ma s) |
Same as allocMutMem
, but also use setMutMem
to reset all of newly allocated memory to
zeros.
- Unsafe
- When precondition for
memCount
argument is violated the outcome is unpredictable. One possible outcome is termination withHeapOverflow
async exception.
Example
>>>
:set -XTypeApplications
>>>
:set -XDataKinds
>>>
import Data.Prim.Memory
>>>
mb <- allocZeroMutMem @Int @(MBytes 'Inc) 10
>>>
b <- freezeMutMem mb
>>>
toListMem b :: [Int]
[0,0,0,0,0,0,0,0,0,0]
Since: 0.3.0
:: (MemAlloc ma, 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) |
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.
Default implementation is defaultReallocMutMem
- Unsafe
- Undefined behavior when
memSource
is used afterwards. The same unsafety notice fromallocMutMem
with regards tomemCount
is applicable here as well.
Since: 0.3.0
withScrubbedMutMem :: forall e ma m a. (MonadUnliftPrim RW m, Prim e, MemAlloc ma, PtrAccess RW (ma RW)) => Count e -> (ma RW -> m a) -> m a Source #
Allocate a new region of memory and Ensure that it is filled with zeros before and
after it gets used. PtrAccess
is not used directly, but instead is used to guarantee
that the memory is pinned and its contents will not get moved around by the garbage
collector.
Since: 0.3.0
defaultReallocMutMem :: (Prim e, MemAlloc ma, MonadPrim s m) => ma s -> Count e -> m (ma s) Source #
An action that can be used as a default implementation for reallocMutMem
. Whenever
current memory region byte count matches the supplied new size exactly then such memory
region is simply returned back and this function is a noop. Otherwise a new memory
region is allocated and all the data that can fit into the new region will be copied
over.
- Unsafe
- Same unsafety notice as in
reallocMutMem
Since: 0.3.0
Thaw/Freeze
thawCloneMem :: forall ma m s. (MemAlloc ma, MonadPrim s m) => FrozenMem ma -> m (ma s) Source #
This is a safe version of thawMem
. It first makes an exact copy of the supplied
memory region and only then thaws it, thus yielding a mutable region of memory. This
means any mutation, will only affect the newly allocated region that was returned and
not the source region.
Examples
>>>
:set -XTypeApplications
>>>
:set -XDataKinds
>>>
import Data.Prim.Memory
>>>
let fm = fromListMem @Word8 @(MBytes 'Inc) [1,2,3,4]
>>>
mm <- thawCloneMem fm
>>>
writeOffMutMem mm 1 (0xadde :: Word16)
>>>
freezeMutMem mm
[0x01,0x02,0xde,0xad]>>>
fm
[0x01,0x02,0x03,0x04]
Since: 0.1.0
:: forall e ma m s. (Prim e, MemAlloc ma, MonadPrim s m) | |
=> FrozenMem ma | memSource - Read-only source memory region from which the data will copied and thawed |
-> Off e | memSourceOff - Offset into source memory in number of elements of type Preconditions: 0 <= memSourceOff unOff memSourceOff < unCount (countMem memSource) |
-> Count e | memCount - Number of elements of type Preconditions: 0 <= memCount unOff memSourceOff + unCount memCount < unCount (countMem memSource) |
-> m (ma s) |
Similar to thawCloneMem
, except it is possible to specify which portion of the
frozen region will be copied over and thawed.
- Unsafe
- When any precondition for eihter an offset
memSourceOff
or the element countmemCount
is violated a call to this function can result in: copy of data that doesn't belong tomemSource
or failure with a segfault.
Examples
>>>
:set -XTypeApplications
>>>
:set -XDataKinds
>>>
import Data.Prim.Memory
>>>
let fm = fromListMem @Word8 @(MBytes 'Inc) [1,2,3,4,5]
>>>
mm <- thawCopyMem fm 1 (3 :: Count Word8)
>>>
writeOffMutMem mm 1 (0 :: Word8)
>>>
freezeMutMem mm
[0x02,0x00,0x04]>>>
fm
[0x01,0x02,0x03,0x04,0x05]
Since: 0.1.0
thawMem :: (MemAlloc ma, MonadPrim s m) => FrozenMem ma -> m (ma s) Source #
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 thawCloneMutMem
for a safe
alternative.
- Unsafe
- This function 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
freezeCloneMutMem :: forall ma m s. (MemAlloc ma, MonadPrim s m) => ma s -> m (FrozenMem ma) Source #
Safe version of freezeMutMem
. Yields an immutable copy of the supplied mutable
memory region. Further mutation of the source memory region will not affect the
produced copy.
freezeCopyMutMem :: forall e ma m s. (Prim e, MemAlloc ma, MonadPrim s m) => ma s -> Off e -> Count e -> m (FrozenMem ma) Source #
freezeMutMem :: (MemAlloc ma, MonadPrim s m) => ma s -> m (FrozenMem ma) Source #
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.3.0
Move
cloneMutMem :: forall ma m s. (MemAlloc ma, MonadPrim s m) => ma s -> m (ma s) Source #
Allocate the same amount of memory as the source memory region and copy all of its data over.
Since: 0.3.0
:: (MemWrite mw, 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 sourceByteCount <- getByteCountMutMem 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 targetByteCount <- getByteCountMutMem memTarget unOffBytes (toByteOff memTargetOff) <= unCount (targetByteCount - byteCountType @e) |
-> Count e | memCount - Number of elements of type Preconditions: 0 <= memCount Both source and target memory regions must have enough memory to perform a copy
of sourceByteCount <- getByteCountMutMem memSource unOff memSourceOff + unCountBytes memCount <= unCount (sourceByteCount - byteCountType @e) targetByteCount <- getByteCountMutMem memTarget 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 countmemCount
is violated a call to this function can result in: copy of data that doesn't belong tomemSourceRead
, heap corruption or failure with a segfault.
Since: 0.3.0
moveByteOffToMBytesMutMem Source #
:: (MemWrite mw, 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 sourceByteCount <- getByteCountMutMem 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 targetByteCount <- getByteCountMutMem memTarget unOffBytes memTargetOff <= unCount (targetByteCount - byteCountType @e) |
-> Count e | memCount - Number of elements of type Preconditions: 0 <= memCount Both source and target memory regions must have enough memory to perform a copy
of sourceByteCount <- getByteCountMutMem memSource unOff memSourceOff + unCountBytes memCount <= unCount (sourceByteCount - byteCountType @e) targetByteCount <- getByteCountMutMem memTarget unOff memTargetOff + unCountBytes memCount <= unCount (targetByteCount - byteCountType @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 countmemCount
is violated a call to this function can result in: copy of data that doesn't belong tomemSource
, heap corruption or failure with a segfault.
Since: 0.3.0
moveByteOffToPtrMutMem Source #
:: (MemWrite mw, 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 sourceByteCount <- getByteCountMutMem memSource unOff (toByteOff memSourceOff) <= unCount (sourceByteCount - byteCountType @e) |
-> Ptr e | memTarget - Target memory into where to copy Precondition: Once the pointer is advanced by |
-> Off Word8 | memTargetOff - Offset in number of bytes into target memory where writing will start Preconditions: 0 <= memTargetOff Once the pointer is advanced by |
-> Count e | memCount - Number of elements of type Preconditions: 0 <= memCount Both source and target memory regions must have enough memory to perform a copy
of sourceByteCount <- getByteCountMutMem memSource unOff memSourceOff + unCountBytes memCount <= unCount (sourceByteCount - 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
ormemTargetOff
, a target pointermemTarget
or the element countmemCount
is violated a call to this function can result in: copy of data that doesn't belong tomemSource
, heap corruption or failure with a segfault.
Since: 0.3.0
Load list
:: 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 |
Same as loadListMutMemN
, 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 <- allocMutMem (5 :: Count Char) :: IO (MBytes 'Inc RW)
>>>
loadListMutMem "HelloWorld" ma
("World",Count {unCount = 5})>>>
freezeMutMem ma
[0x48,0x00,0x00,0x00,0x65,0x00,0x00,0x00,0x6c,0x00,0x00,0x00,0x6c,0x00,0x00,0x00,0x6f,0x00,0x00,0x00]>>>
loadListMutMem (replicate 6 (0xff :: Word8)) ma
([],Count {unCount = 6})>>>
freezeMutMem ma
[0xff,0xff,0xff,0xff,0xff,0xff,0x00,0x00,0x6c,0x00,0x00,0x00,0x6c,0x00,0x00,0x00,0x6f,0x00,0x00,0x00]
Since: 0.3.0
:: 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 () |
Same as loadListMutMem
, but ignores the result. Equivalence as property:
let c = fromInteger (abs i) :: Count Int in (createZeroMemST_ c (loadListMutMem_ (xs :: [Int])) :: Bytes 'Inc) == createZeroMemST_ c (void . loadListMutMem xs)
Since: 0.2.0
:: 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 targetCount <- getCountMutMem 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 |
Same as loadListOffMutMemN
, 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
:: 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 targetCount <- getCountMutMem memTarget elemCount <= targetCount |
-> [e] | listSource - List with elements that should be loaded |
-> mw s | memTarget - Memory region where to load the elements into |
-> m () |
Same as loadListMutMemN
, 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
With offset
:: 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 targetCount <- getCountMutMem memTarget unOff memTargetOff < unCount targetCount |
-> m ([e], Count e) | Leftover part of the |
Same as loadListOffMutMemN
, 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.3.0
:: (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 targetCount <- getCountMutMem 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 targetCount <- getByteCountMutMem memTarget unOff memTargetOff < unCount targetCount |
-> m ([e], Count e) | Leftover part of the |
Same as loadListByteOffMutMemN
, but works with offset in number of elements instead of
bytes.
- Unsafe
- When preconditions for either the offset
memTargetOff
or the element countmemCount
is violated then a call to this function can result in heap corruption or failure with a segfault.
Since: 0.2.0
loadListByteOffMutMem Source #
:: (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 targetByteCount <- getByteCountMutMem memTarget unOff memTargetOff <= unCount (targetByteCount - byteCountType @e) |
-> m ([e], Count e) | Leftover part of the |
Same as loadListByteOffMutMemN
, 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 <- allocZeroMutMem (5 :: Count Char) :: IO (MBytes 'Inc RW)
>>>
freezeMutMem ma
[0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00]>>>
loadListByteOffMutMem "Hello World" ma 0
(" World",Count {unCount = 5})>>>
freezeMutMem ma
[0x48,0x00,0x00,0x00,0x65,0x00,0x00,0x00,0x6c,0x00,0x00,0x00,0x6c,0x00,0x00,0x00,0x6f,0x00,0x00,0x00]>>>
loadListByteOffMutMem ([0xff,0xff,0xff] :: [Word8]) ma 1
([],Count {unCount = 3})>>>
freezeMutMem ma
[0x48,0xff,0xff,0xff,0x65,0x00,0x00,0x00,0x6c,0x00,0x00,0x00,0x6c,0x00,0x00,0x00,0x6f,0x00,0x00,0x00]
Since: 0.3.0
loadListByteOffMutMemN Source #
:: (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 targetByteCount <- getByteCountMutMem 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 targetByteCount <- getByteCountMutMem memTarget unOff memTargetOff <= unCount (targetByteCount - byteCountType @e) |
-> m ([e], Count e) | Leftover part of the |
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 countmemCount
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 <- allocZeroMutMem (6 :: Count Char) :: IO (MBytes 'Inc RW)
>>>
loadListByteOffMutMemN 4 "Hello!" ma (toByteOff (1 :: Off Char))
("o!",Count {unCount = 4})>>>
freezeMutMem 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 useful like loading prefixes from nested lists:
>>>
import Control.Monad
>>>
foldM_ (\o xs -> (+ o) . countToByteOff . snd <$> loadListByteOffMutMemN 4 xs ma o) 2 [[x..] | x <- [1..5] :: [Word8]]
>>>
freezeMutMem 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