{-# LANGUAGE BangPatterns #-}
{-# LANGUAGE DataKinds #-}
{-# LANGUAGE FlexibleContexts #-}
{-# LANGUAGE FlexibleInstances #-}
{-# LANGUAGE KindSignatures #-}
{-# LANGUAGE MultiParamTypeClasses #-}
{-# LANGUAGE RankNTypes #-}
{-# LANGUAGE RoleAnnotations #-}
{-# LANGUAGE ScopedTypeVariables #-}
{-# LANGUAGE TypeFamilies #-}
{-# LANGUAGE TypeFamilyDependencies #-}
{-# LANGUAGE UndecidableInstances #-}
{-# OPTIONS_GHC -fno-warn-orphans #-}
module Data.Prim.Memory.Internal
( Bytes(..)
, MBytes(..)
, Pinned(..)
, module Data.Prim.Memory.Internal
) where
import Control.Exception
import Data.List.NonEmpty (NonEmpty(..))
import Control.Monad.ST
import Control.Prim.Monad
import Control.Prim.Monad.Unsafe
import Data.Foldable as Foldable
import Data.Prim
import Data.Prim.Memory.Bytes.Internal
( Bytes(..)
, MBytes(..)
, Pinned(..)
, allocMBytes
, reallocMBytes
, byteCountBytes
, compareByteOffBytes
, copyByteOffBytesToMBytes
, freezeMBytes
, getByteCountMBytes
, indexByteOffBytes
, indexOffBytes
, isSameBytes
, moveByteOffMBytesToMBytes
, readByteOffMBytes
, readOffMBytes
, setMBytes
, thawBytes
, writeByteOffMBytes
, writeOffMBytes
)
import Data.List as List
import Data.Prim.Memory.ByteString
import Data.Prim.Memory.ForeignPtr
import Data.Prim.Memory.Ptr
import Foreign.Prim
import Numeric (showHex)
import qualified Data.Semigroup as Semigroup
import qualified Data.Monoid as Monoid
import Data.Kind
class MemRead r where
byteCountMem :: r -> Count Word8
indexOffMem :: Prim e => r -> Off e -> e
indexByteOffMem :: Prim e => r -> Off Word8 -> e
copyByteOffToMBytesMem ::
(MonadPrim s m, Prim e) => r -> Off Word8 -> MBytes p s -> Off Word8 -> Count e -> m ()
copyByteOffToPtrMem ::
(MonadPrim s m, Prim e) => r -> Off Word8 -> Ptr e -> Off Word8 -> Count e -> m ()
compareByteOffToPtrMem ::
(MonadPrim s m, Prim e) => r -> Off Word8 -> Ptr e -> Off Word8 -> Count e -> m Ordering
compareByteOffToBytesMem ::
(MonadPrim s m, Prim e) => r -> Off Word8 -> Bytes p -> Off Word8 -> Count e -> m Ordering
compareByteOffMem ::
(MemRead r', Prim e) => r' -> Off Word8 -> r -> Off Word8 -> Count e -> Ordering
class (MemRead (FrozenMem a), MemWrite a) => MemAlloc a where
type FrozenMem a = (fa :: Type) | fa -> a
getByteCountMem :: MonadPrim s m => a s -> m (Count Word8)
allocByteCountMem :: MonadPrim s m => Count Word8 -> m (a s)
thawMem :: MonadPrim s m => FrozenMem a -> m (a s)
freezeMem :: MonadPrim s m => a s -> m (FrozenMem a)
resizeMem :: (MonadPrim s m, Prim e) => a s -> Count e -> m (a s)
resizeMem = defaultResizeMem
class MemWrite w where
readOffMem :: (MonadPrim s m, Prim e) => w s -> Off e -> m e
readByteOffMem :: (MonadPrim s m, Prim e) => w s -> Off Word8 -> m e
writeOffMem :: (MonadPrim s m, Prim e) => w s -> Off e -> e -> m ()
writeByteOffMem :: (MonadPrim s m, Prim e) => w s -> Off Word8 -> e -> m ()
moveByteOffToMBytesMem ::
(MonadPrim s m, Prim e) => w s -> Off Word8 -> MBytes p s -> Off Word8 -> Count e -> m ()
moveByteOffToPtrMem ::
(MonadPrim s m, Prim e) => w s -> Off Word8 -> Ptr e -> Off Word8 -> Count e -> m ()
copyByteOffMem ::
(MonadPrim s m, MemRead r, Prim e) => r -> Off Word8 -> w s -> Off Word8 -> Count e -> m ()
moveByteOffMem ::
(MonadPrim s m, MemWrite w', Prim e) => w' s -> Off Word8 -> w s -> Off Word8 -> Count e -> m ()
setMem
:: (MonadPrim s m, Prim e)
=> w s
-> Off e
-> Count e
-> e
-> m ()
instance MemRead ByteString where
byteCountMem (PS _ _ c) = Count c
{-# INLINE byteCountMem #-}
indexOffMem bs i = unsafeInlineIO $ withPtrAccess bs (`readOffPtr` i)
{-# INLINE indexOffMem #-}
indexByteOffMem bs i = unsafeInlineIO $ withPtrAccess bs (`readByteOffPtr` i)
{-# INLINE indexByteOffMem #-}
copyByteOffToMBytesMem bs srcOff mb dstOff c =
withPtrAccess bs $ \srcPtr -> copyByteOffPtrToMBytes srcPtr srcOff mb dstOff c
{-# INLINE copyByteOffToMBytesMem #-}
copyByteOffToPtrMem bs srcOff dstPtr dstOff c =
withPtrAccess bs $ \srcPtr -> copyByteOffPtrToPtr srcPtr srcOff dstPtr dstOff c
{-# INLINE copyByteOffToPtrMem #-}
compareByteOffToPtrMem bs off1 ptr2 off2 c =
withPtrAccess bs $ \ptr1 -> pure $ compareByteOffPtrToPtr ptr1 off1 ptr2 off2 c
{-# INLINE compareByteOffToPtrMem #-}
compareByteOffToBytesMem bs off1 bytes off2 c =
withPtrAccess bs $ \ptr1 -> pure $ compareByteOffPtrToBytes ptr1 off1 bytes off2 c
{-# INLINE compareByteOffToBytesMem #-}
compareByteOffMem mem1 off1 bs off2 c =
unsafeInlineIO $ withPtrAccess bs $ \ptr2 -> compareByteOffToPtrMem mem1 off1 ptr2 off2 c
{-# INLINE compareByteOffMem #-}
instance MemAlloc MByteString where
type FrozenMem MByteString = ByteString
getByteCountMem (MByteString (PS _ _ c)) = pure $ Count c
{-# INLINE getByteCountMem #-}
allocByteCountMem c = do
fp <- mallocByteCountPlainForeignPtr c
pure $ MByteString (PS fp 0 (coerce c))
{-# INLINE allocByteCountMem #-}
thawMem bs = pure $ MByteString bs
{-# INLINE thawMem #-}
freezeMem (MByteString bs) = pure bs
{-# INLINE freezeMem #-}
resizeMem bsm@(MByteString (PS fp o n)) newc
| newn > n = defaultResizeMem bsm newc
| otherwise = pure $ MByteString (PS fp o newn)
where
Count newn = toByteCount newc
{-# INLINE resizeMem #-}
instance MemWrite MByteString where
readOffMem (MByteString mbs) i = withPtrAccess mbs (`readOffPtr` i)
{-# INLINE readOffMem #-}
readByteOffMem (MByteString mbs) i = withPtrAccess mbs (`readByteOffPtr` i)
{-# INLINE readByteOffMem #-}
writeOffMem (MByteString mbs) i a = withPtrAccess mbs $ \ptr -> writeOffPtr ptr i a
{-# INLINE writeOffMem #-}
writeByteOffMem (MByteString mbs) i a = withPtrAccess mbs $ \ptr -> writeByteOffPtr ptr i a
{-# INLINE writeByteOffMem #-}
moveByteOffToPtrMem (MByteString fsrc) srcOff dstPtr dstOff c =
withPtrAccess fsrc $ \srcPtr -> moveByteOffPtrToPtr srcPtr srcOff dstPtr dstOff c
{-# INLINE moveByteOffToPtrMem #-}
moveByteOffToMBytesMem (MByteString fsrc) srcOff dst dstOff c =
withPtrAccess fsrc $ \srcPtr -> moveByteOffPtrToMBytes srcPtr srcOff dst dstOff c
{-# INLINE moveByteOffToMBytesMem #-}
copyByteOffMem src srcOff (MByteString fdst) dstOff c =
withPtrAccess fdst $ \dstPtr -> copyByteOffToPtrMem src srcOff dstPtr dstOff c
{-# INLINE copyByteOffMem #-}
moveByteOffMem src srcOff (MByteString fdst) dstOff c =
withPtrAccess fdst $ \dstPtr -> moveByteOffToPtrMem src srcOff dstPtr dstOff c
{-# INLINE moveByteOffMem #-}
setMem (MByteString mbs) off c a = withPtrAccess mbs $ \ptr -> setOffPtr ptr off c a
{-# INLINE setMem #-}
instance MemRead ShortByteString where
byteCountMem = byteCountMem . fromShortByteStringBytes
{-# INLINE byteCountMem #-}
indexOffMem sbs = indexOffMem (fromShortByteStringBytes sbs)
{-# INLINE indexOffMem #-}
indexByteOffMem sbs = indexByteOffMem (fromShortByteStringBytes sbs)
{-# INLINE indexByteOffMem #-}
copyByteOffToMBytesMem sbs = copyByteOffToMBytesMem (fromShortByteStringBytes sbs)
{-# INLINE copyByteOffToMBytesMem #-}
copyByteOffToPtrMem sbs = copyByteOffToPtrMem (fromShortByteStringBytes sbs)
{-# INLINE copyByteOffToPtrMem #-}
compareByteOffToPtrMem sbs = compareByteOffToPtrMem (fromShortByteStringBytes sbs)
{-# INLINE compareByteOffToPtrMem #-}
compareByteOffToBytesMem sbs = compareByteOffToBytesMem (fromShortByteStringBytes sbs)
{-# INLINE compareByteOffToBytesMem #-}
compareByteOffMem mem off1 sbs = compareByteOffMem mem off1 (fromShortByteStringBytes sbs)
{-# INLINE compareByteOffMem #-}
newtype MemState a s = MemState { unMemState :: a }
instance MemWrite (MemState (ForeignPtr a)) where
readOffMem (MemState fptr) i = withForeignPtr fptr $ \ptr -> readOffPtr (castPtr ptr) i
{-# INLINE readOffMem #-}
readByteOffMem (MemState fptr) i =
withForeignPtr fptr $ \ptr -> readByteOffPtr (castPtr ptr) i
{-# INLINE readByteOffMem #-}
writeOffMem (MemState fptr) i a = withForeignPtr fptr $ \ptr -> writeOffPtr (castPtr ptr) i a
{-# INLINE writeOffMem #-}
writeByteOffMem (MemState fptr) i a =
withForeignPtr fptr $ \ptr -> writeByteOffPtr (castPtr ptr) i a
{-# INLINE writeByteOffMem #-}
moveByteOffToPtrMem (MemState fsrc) srcOff dstPtr dstOff c =
withForeignPtr fsrc $ \srcPtr -> moveByteOffPtrToPtr (castPtr srcPtr) srcOff dstPtr dstOff c
{-# INLINE moveByteOffToPtrMem #-}
moveByteOffToMBytesMem (MemState fsrc) srcOff dst dstOff c =
withForeignPtr fsrc $ \srcPtr -> moveByteOffPtrToMBytes (castPtr srcPtr) srcOff dst dstOff c
{-# INLINE moveByteOffToMBytesMem #-}
copyByteOffMem src srcOff (MemState fdst) dstOff c =
withForeignPtr fdst $ \dstPtr ->
copyByteOffToPtrMem src srcOff (castPtr dstPtr) dstOff c
{-# INLINE copyByteOffMem #-}
moveByteOffMem src srcOff (MemState fdst) dstOff c =
withForeignPtr fdst $ \dstPtr ->
moveByteOffToPtrMem src srcOff (castPtr dstPtr) dstOff c
{-# INLINE moveByteOffMem #-}
setMem (MemState fptr) off c a = withForeignPtr fptr $ \ptr -> setOffPtr (castPtr ptr) off c a
{-# INLINE setMem #-}
modifyFetchOldMem ::
(MemWrite w, MonadPrim s m, Prim b) => w s -> Off b -> (b -> b) -> m b
modifyFetchOldMem mem o f = modifyFetchOldMemM mem o (pure . f)
{-# INLINE modifyFetchOldMem #-}
modifyFetchNewMem ::
(MemWrite w, MonadPrim s m, Prim b) => w s -> Off b -> (b -> b) -> m b
modifyFetchNewMem mem o f = modifyFetchNewMemM mem o (pure . f)
{-# INLINE modifyFetchNewMem #-}
modifyFetchOldMemM ::
(MemWrite w, MonadPrim s m, Prim b) => w s -> Off b -> (b -> m b) -> m b
modifyFetchOldMemM mem o f = do
a <- readOffMem mem o
a <$ (writeOffMem mem o =<< f a)
{-# INLINE modifyFetchOldMemM #-}
modifyFetchNewMemM ::
(MemWrite w, MonadPrim s m, Prim b) => w s -> Off b -> (b -> m b) -> m b
modifyFetchNewMemM mem o f = do
a <- readOffMem mem o
a' <- f a
a' <$ writeOffMem mem o a'
{-# INLINE modifyFetchNewMemM #-}
defaultResizeMem ::
(Prim e, MemAlloc a, MonadPrim s m) => a s -> Count e -> m (a s)
defaultResizeMem mem c = do
let newByteCount = toByteCount c
oldByteCount <- getByteCountMem mem
if oldByteCount == newByteCount
then pure mem
else do
newMem <- allocByteCountMem newByteCount
newMem <$ moveMem mem 0 newMem 0 oldByteCount
cycleMemN :: (MemAlloc a, MemRead r) => Int -> r -> FrozenMem a
cycleMemN n r
| n <= 0 = emptyMem
| otherwise =
runST $ do
let bc@(Count chunk) = byteCountMem r
c@(Count c8) = Count n * bc
mem <- allocByteCountMem c
let go i = when (i < c8) $ copyByteOffMem r 0 mem (Off i) bc >> go (i + chunk)
go 0
freezeMem mem
{-# INLINE cycleMemN #-}
emptyMem :: MemAlloc a => FrozenMem a
emptyMem = createMemST_ (0 :: Count Word8) (\_ -> pure ())
{-# INLINE emptyMem #-}
singletonMem ::
forall e a. (MemAlloc a, Prim e)
=> e
-> FrozenMem a
singletonMem a = createMemST_ (1 :: Count e) $ \mem -> writeOffMem mem 0 a
{-# INLINE singletonMem #-}
allocMem :: (MemAlloc a, MonadPrim s m, Prim e) => Count e -> m (a s)
allocMem n = allocByteCountMem (toByteCount n)
{-# INLINE allocMem #-}
allocZeroMem ::
(MemAlloc a, MonadPrim s m, Prim e) => Count e -> m (a s)
allocZeroMem n = do
m <- allocMem n
m <$ setMem m 0 (toByteCount n) (0 :: Word8)
{-# INLINE allocZeroMem #-}
createMemST :: (MemAlloc a, Prim e) => Count e -> (forall s . a s -> ST s b) -> (b, FrozenMem a)
createMemST n f = runST $ do
m <- allocMem n
res <- f m
i <- freezeMem m
pure (res, i)
{-# INLINE createMemST #-}
createMemST_ :: (MemAlloc a, Prim e) => Count e -> (forall s . a s -> ST s b) -> FrozenMem a
createMemST_ n f = runST (allocMem n >>= \m -> f m >> freezeMem m)
{-# INLINE createMemST_ #-}
createZeroMemST :: (MemAlloc a, Prim e) => Count e -> (forall s . a s -> ST s b) -> (b, FrozenMem a)
createZeroMemST n f = runST $ do
m <- allocZeroMem n
res <- f m
i <- freezeMem m
pure (res, i)
{-# INLINE createZeroMemST #-}
createZeroMemST_ :: (MemAlloc a, Prim e) => Count e -> (forall s . a s -> ST s b) -> FrozenMem a
createZeroMemST_ n f = runST (allocZeroMem n >>= \m -> f m >> freezeMem m)
{-# INLINE createZeroMemST_ #-}
copyMem ::
(MonadPrim s m, MemRead r, MemWrite w, Prim e)
=> r
-> Off e
-> w s
-> Off e
-> Count e
-> m ()
copyMem src srcOff dst dstOff = copyByteOffMem src (toByteOff srcOff) dst (toByteOff dstOff)
{-# INLINE copyMem #-}
moveMem ::
(MonadPrim s m, MemWrite w1, MemWrite w2, Prim e)
=> w1 s
-> Off e
-> w2 s
-> Off e
-> Count e
-> m ()
moveMem src srcOff dst dstOff = moveByteOffMem src (toByteOff srcOff) dst (toByteOff dstOff)
{-# INLINE moveMem #-}
appendMem :: (MemRead r1, MemRead r2, MemAlloc a) => r1 -> r2 -> FrozenMem a
appendMem r1 r2 =
createMemST_ (n1 + n2) $ \mem -> do
copyMem r1 0 mem 0 n1
copyMem r2 (coerce n1) mem (coerce n1) n2
where
n1 = byteCountMem r1
n2 = byteCountMem r2
{-# INLINABLE appendMem #-}
concatMem :: (MemRead r, MemAlloc a) => [r] -> FrozenMem a
concatMem xs = do
let c = Foldable.foldl' (\ !acc b -> acc + byteCountMem b) 0 xs
createMemST_ c $ \mb -> do
let load i b = do
let cb@(Count n) = byteCountMem b :: Count Word8
(i + Off n) <$ copyMem b 0 mb i cb
foldM_ load 0 xs
{-# INLINABLE concatMem #-}
thawCopyMem ::
(MemRead r, MemAlloc a, MonadPrim s m, Prim e) => r -> Off e -> Count e -> m (a s)
thawCopyMem a off c = do
mem <- allocMem c
mem <$ copyMem a off mem 0 c
{-# INLINE thawCopyMem #-}
freezeCopyMem ::
(MemAlloc a, MonadPrim s m, Prim e)
=> a s
-> Off e
-> Count e
-> m (FrozenMem a)
freezeCopyMem mem off c = freezeMem mem >>= \r -> thawCopyMem r off c >>= freezeMem
{-# INLINE freezeCopyMem #-}
thawCloneMem :: (MemRead r, MemAlloc a, MonadPrim s m) => r -> m (a s)
thawCloneMem a = thawCopyMem a 0 (byteCountMem a)
{-# INLINE thawCloneMem #-}
freezeCloneMem :: (MemAlloc a, MonadPrim s m) => a s -> m (FrozenMem a)
freezeCloneMem = freezeMem >=> thawCloneMem >=> freezeMem
{-# INLINE freezeCloneMem #-}
convertMem :: (MemRead r, MemAlloc a) => r -> FrozenMem a
convertMem a = runST $ thawCloneMem a >>= freezeMem
{-# INLINE convertMem #-}
countMem ::
forall e r. (MemRead r, Prim e)
=> r
-> Count e
countMem = fromByteCount . byteCountMem
{-# INLINE countMem #-}
countRemMem :: forall e r. (MemRead r, Prim e) => r -> (Count e, Count Word8)
countRemMem = fromByteCountRem . byteCountMem
{-# INLINE countRemMem #-}
getCountMem :: (MemAlloc r, MonadPrim s m, Prim e) => r s -> m (Count e)
getCountMem = fmap (fromByteCount . coerce) . getByteCountMem
{-# INLINE getCountMem #-}
getCountRemMem :: (MemAlloc r, MonadPrim s m, Prim e) => r s -> m (Count e, Count Word8)
getCountRemMem = fmap (fromByteCountRem . coerce) . getByteCountMem
{-# INLINE getCountRemMem #-}
clone :: (MemAlloc r, MonadPrim s m) => r s -> m (r s)
clone mb = do
n <- getByteCountMem mb
mb' <- allocMem n
mb' <$ moveMem mb 0 mb' 0 n
{-# INLINE clone #-}
eqMem :: (MemRead r1, MemRead r2) => r1 -> r2 -> Bool
eqMem b1 b2 = n == byteCountMem b2 && compareByteOffMem b1 0 b2 0 n == EQ
where
n = byteCountMem b1
{-# INLINE eqMem #-}
compareMem ::
(MemRead r1, MemRead r2, Prim e)
=> r1
-> Off e
-> r2
-> Off e
-> Count e
-> Ordering
compareMem r1 off1 r2 off2 = compareByteOffMem r1 (toByteOff off1) r2 (toByteOff off2)
{-# INLINE compareMem #-}
toListMem :: (MemRead r, Prim e) => r -> [e]
toListMem ba = build (\ c n -> foldrCountMem (countMem ba) c n ba)
{-# INLINE toListMem #-}
{-# SPECIALIZE toListMem :: Prim e => Bytes p -> [e] #-}
toListSlackMem ::
forall e r. (MemRead r, Prim e)
=> r
-> ([e], [Word8])
toListSlackMem mem =
(build (\c n -> foldrCountMem k c n mem), getSlack (k8 + r8) [])
where
(k, Count r8) = countRemMem mem
Count k8 = toByteCount k
getSlack i !acc
| i == k8 = acc
| otherwise =
let i' = i - 1
in getSlack i' (indexByteOffMem mem (Off i') : acc)
{-# INLINABLE toListSlackMem #-}
foldrCountMem :: (MemRead r, Prim e) => Count e -> (e -> b -> b) -> b -> r -> b
foldrCountMem (Count k) c nil bs = go 0
where
go i
| i == k = nil
| otherwise =
let !v = indexOffMem bs (Off i)
in v `c` go (i + 1)
{-# INLINE[0] foldrCountMem #-}
loadListMemN ::
(MemWrite r, MonadPrim s m, Prim e)
=> Count e
-> Count Word8
-> [e]
-> r s
-> m Ordering
loadListMemN (Count n) (Count slack) ys mb = do
let go [] !i = pure (compare i n <> compare 0 slack)
go (x:xs) !i
| i < n = writeOffMem mb (Off i) x >> go xs (i + 1)
| otherwise = pure GT
go ys 0
{-# INLINABLE loadListMemN #-}
loadListMemN_ :: (MemWrite r, MonadPrim s m, Prim e) => Count e -> [e] -> r s -> m ()
loadListMemN_ (Count n) ys mb =
let go [] _ = pure ()
go (x:xs) i = when (i < n) $ writeOffMem mb (Off i) x >> go xs (i + 1)
in go ys 0
{-# INLINABLE loadListMemN_ #-}
loadListMem :: (MonadPrim s m, MemAlloc r, Prim e) => [e] -> r s -> m Ordering
loadListMem ys mb = do
(c, slack) <- getCountRemMem mb
loadListMemN (countAsProxy ys c) slack ys mb
{-# INLINE loadListMem #-}
loadListMem_ :: (MonadPrim s m, MemAlloc r, Prim e) => [e] -> r s -> m ()
loadListMem_ ys mb = do
c <- getCountMem mb
loadListMemN_ (countAsProxy ys c) ys mb
{-# INLINE loadListMem_ #-}
fromListMemN :: (MemAlloc a, Prim e) => Count e -> [e] -> (Ordering, FrozenMem a)
fromListMemN n xs = createMemST n (loadListMemN n 0 xs)
{-# INLINE fromListMemN #-}
fromListMemN_ :: (MemAlloc a, Prim e) => Count e -> [e] -> FrozenMem a
fromListMemN_ !n xs = createMemST_ n (loadListMemN_ n xs)
{-# INLINE fromListMemN_ #-}
fromListMem :: (MemAlloc a, Prim e) => [e] -> FrozenMem a
fromListMem xs = fromListMemN_ (countAsProxy xs (coerce (length xs))) xs
{-# INLINE fromListMem #-}
fromByteListMem :: MemAlloc a => [Word8] -> FrozenMem a
fromByteListMem = fromListMem
{-# INLINE fromByteListMem #-}
toByteListMem :: MemAlloc a => FrozenMem a -> [Word8]
toByteListMem = toListMem
{-# INLINE toByteListMem #-}
mapByteMem :: (MemRead r, MemAlloc a, Prim e) => (Word8 -> e) -> r -> FrozenMem a
mapByteMem f = mapByteOffMem (const f)
mapByteOffMem ::
(MemRead r, MemAlloc a, Prim e) => (Off Word8 -> Word8 -> e) -> r -> FrozenMem a
mapByteOffMem f r = runST $ mapByteOffMemM (\i -> pure . f i) r
mapByteMemM ::
(MemRead r, MemAlloc a, MonadPrim s m, Prim e)
=> (Word8 -> m e)
-> r
-> m (FrozenMem a)
mapByteMemM f = mapByteOffMemM (const f)
mapByteOffMemM ::
(MemRead r, MemAlloc a, MonadPrim s m, Prim e)
=> (Off Word8 -> Word8 -> m e)
-> r
-> m (FrozenMem a)
mapByteOffMemM f r = do
let bc@(Count n) = byteCountMem r
c = countAsProxy (f 0 0) (Count n)
mem <- allocMem c
_ <- forByteOffMemM_ r 0 bc f
freezeMem mem
forByteOffMemM_ ::
(MemRead r, MonadPrim s m, Prim e)
=> r
-> Off Word8
-> Count e
-> (Off Word8 -> e -> m b)
-> m (Off Word8)
forByteOffMemM_ r (Off byteOff) c f =
let n = coerce (toByteCount c) + byteOff
Count k = byteCountProxy c
go i
| i < n = f (Off i) (indexByteOffMem r (Off i)) >> go (i + k)
| otherwise = pure $ Off i
in go byteOff
loopShortM :: Monad m => Int -> (Int -> a -> Bool) -> (Int -> Int) -> a -> (Int -> a -> m a) -> m a
loopShortM !startAt condition increment !initAcc f = go startAt initAcc
where
go !step !acc
| condition step acc = f step acc >>= go (increment step)
| otherwise = pure acc
{-# INLINE loopShortM #-}
loopShortM' :: Monad m => Int -> (Int -> a -> m Bool) -> (Int -> Int) -> a -> (Int -> a -> m a) -> m a
loopShortM' !startAt condition increment !initAcc f = go startAt initAcc
where
go !step !acc =
condition step acc >>= \cont ->
if cont
then f step acc >>= go (increment step)
else pure acc
{-# INLINE loopShortM' #-}
data MemView a = MemView
{ mvOffset :: {-# UNPACK #-} !(Off Word8)
, mvCount :: {-# UNPACK #-} !(Count Word8)
, mvMem :: !a
}
data MMemView a s = MMemView
{ mmvOffset :: {-# UNPACK #-} !(Off Word8)
, mmvCount :: {-# UNPACK #-} !(Count Word8)
, mmvMem :: !(a s)
}
izipWithByteOffMemM_ ::
(MemRead r1, MemRead r2, MonadPrim s m, Prim e)
=> r1
-> Off Word8
-> r2
-> Off Word8
-> Count e
-> (Off Word8 -> e -> Off Word8 -> e -> m b)
-> m (Off Word8)
izipWithByteOffMemM_ r1 (Off byteOff1) r2 off2 c f =
let n = coerce (toByteCount c) + byteOff1
Count k = byteCountProxy c
go i
| i < n =
let o1 = Off i
o2 = Off i + off2
in f o1 (indexByteOffMem r1 o1) o2 (indexByteOffMem r2 o2) >>
go (i + k)
| otherwise = pure $ Off i
in go byteOff1
izipWithOffMemM_ ::
(MemRead r1, MemRead r2, MonadPrim s m, Prim e1, Prim e2)
=> r1
-> Off e1
-> r2
-> Off e2
-> Int
-> (Off e1 -> e1 -> Off e2 -> e2 -> m b)
-> m ()
izipWithOffMemM_ r1 off1 r2 off2 nc f =
let n = nc + coerce off1
go o1@(Off i) o2 =
when (i < n) $
f o1 (indexOffMem r1 o1) o2 (indexOffMem r2 o2) >> go (o1 + 1) (o2 + 1)
in go off1 off2
instance MemRead (Bytes p) where
byteCountMem = byteCountBytes
{-# INLINE byteCountMem #-}
indexOffMem = indexOffBytes
{-# INLINE indexOffMem #-}
indexByteOffMem = indexByteOffBytes
{-# INLINE indexByteOffMem #-}
copyByteOffToMBytesMem = copyByteOffBytesToMBytes
{-# INLINE copyByteOffToMBytesMem #-}
copyByteOffToPtrMem = copyByteOffBytesToPtr
{-# INLINE copyByteOffToPtrMem #-}
compareByteOffToPtrMem bytes1 off1 ptr2 off2 c =
pure $ compareByteOffBytesToPtr bytes1 off1 ptr2 off2 c
{-# INLINE compareByteOffToPtrMem #-}
compareByteOffToBytesMem bytes1 off1 bytes2 off2 c =
pure $ compareByteOffBytes bytes1 off1 bytes2 off2 c
{-# INLINE compareByteOffToBytesMem #-}
compareByteOffMem mem1 off1 bs off2 c =
unsafeInlineIO $ compareByteOffToBytesMem mem1 off1 bs off2 c
{-# INLINE compareByteOffMem #-}
instance Typeable p => MemAlloc (MBytes p) where
type FrozenMem (MBytes p) = Bytes p
getByteCountMem = getByteCountMBytes
{-# INLINE getByteCountMem #-}
allocByteCountMem = allocMBytes
{-# INLINE allocByteCountMem #-}
thawMem = thawBytes
{-# INLINE thawMem #-}
freezeMem = freezeMBytes
{-# INLINE freezeMem #-}
resizeMem = reallocMBytes
{-# INLINE resizeMem #-}
instance MemWrite (MBytes p) where
readOffMem = readOffMBytes
{-# INLINE readOffMem #-}
readByteOffMem = readByteOffMBytes
{-# INLINE readByteOffMem #-}
writeOffMem = writeOffMBytes
{-# INLINE writeOffMem #-}
writeByteOffMem = writeByteOffMBytes
{-# INLINE writeByteOffMem #-}
moveByteOffToPtrMem = moveByteOffMBytesToPtr
{-# INLINE moveByteOffToPtrMem #-}
moveByteOffToMBytesMem = moveByteOffMBytesToMBytes
{-# INLINE moveByteOffToMBytesMem #-}
moveByteOffMem = moveByteOffToMBytesMem
{-# INLINE moveByteOffMem #-}
copyByteOffMem = copyByteOffToMBytesMem
{-# INLINE copyByteOffMem #-}
setMem = setMBytes
{-# INLINE setMem #-}
instance Show (Bytes p) where
show b =
Foldable.foldr' ($) "]" $
('[' :) : List.intersperse (',' :) (map (("0x" ++) .) (showsHexMem b))
instance Typeable p => IsList (Bytes p) where
type Item (Bytes p) = Word8
fromList = fromListMem
fromListN n = fromListMemN_ (Count n)
toList = toListMem
instance Eq (Bytes p) where
b1 == b2 = isSameBytes b1 b2 || eqMem b1 b2
instance Ord (Bytes p) where
compare b1 b2 =
compare n (byteCountBytes b2) <> compareByteOffBytes b1 0 b2 0 n
where
n = byteCountBytes b1
instance Typeable p => Semigroup.Semigroup (Bytes p) where
(<>) = appendMem
sconcat (x :| xs) = concatMem (x:xs)
stimes i = cycleMemN (fromIntegral i)
instance Typeable p => Monoid.Monoid (Bytes p) where
mappend = appendMem
mconcat = concatMem
mempty = emptyMem
showsHexMem :: MemRead r => r -> [ShowS]
showsHexMem b = map toHex (toListMem b :: [Word8])
where
toHex b8 =
(if b8 <= 0x0f
then ('0' :)
else id) .
showHex b8
withScrubbedMem ::
(MonadUnliftPrim RW m, Prim e, MemAlloc mem)
=> Count e
-> (mem RW -> m a)
-> m a
withScrubbedMem c f = do
mem <- allocZeroMem c
f mem `finallyPrim` setMem mem 0 (toByteCount c) 0
where
finallyPrim m1 m2 = withRunInPrimBase $ \run -> finally (run m1) (run m2)