on master help sign in
Create a separate MutByteArray module
dc58c59Harendra Kumar
core/src/Streamly/Internal/Data/Array/Type.hs+1−1
@@ -121,7 +121,7 @@ import qualified Streamly.Internal.Data.MutArray.Type as MA
121import qualified Streamly.Internal.Data.Stream.Type as D
121import qualified Streamly.Internal.Data.Stream.Type as D
122import qualified Streamly.Internal.Data.Stream.Generate as D
122import qualified Streamly.Internal.Data.Stream.Generate as D
123import qualified Streamly.Internal.Data.StreamK.Type as K
123import qualified Streamly.Internal.Data.StreamK.Type as K
124−import qualified Streamly.Internal.Data.Unbox as Unboxed
124+import qualified Streamly.Internal.Data.MutByteArray as Unboxed
125import qualified Streamly.Internal.Data.Unfold.Type as Unfold
125import qualified Streamly.Internal.Data.Unfold.Type as Unfold
126import qualified Text.ParserCombinators.ReadPrec as ReadPrec
126import qualified Text.ParserCombinators.ReadPrec as ReadPrec
127
127
core/src/Streamly/Internal/Data/IORef/Unboxed.hs+3−7
@@ -38,14 +38,10 @@ where
38
38
39#include "inline.hs"
39#include "inline.hs"
40
40
41−import Data.Proxy (Proxy(..))
42import Control.Monad.IO.Class (MonadIO(..))
41import Control.Monad.IO.Class (MonadIO(..))
43−import Streamly.Internal.Data.Unbox
42+import Data.Proxy (Proxy(..))
44− ( MutByteArray(..)
43+import Streamly.Internal.Data.MutByteArray (MutByteArray(..), newByteArray)
45− , Unbox(..)
44+import Streamly.Internal.Data.Unbox (Unbox(..), sizeOf)
46− , newByteArray
47− , sizeOf
48− )
49
45
50import qualified Streamly.Internal.Data.Stream.Type as D
46import qualified Streamly.Internal.Data.Stream.Type as D
51
47
core/src/Streamly/Internal/Data/MutArray/Type.hs+3−3
@@ -239,14 +239,14 @@ import Data.Proxy (Proxy(..))
239import Data.Word (Word8)
239import Data.Word (Word8)
240import Foreign.C.Types (CSize(..), CInt(..))
240import Foreign.C.Types (CSize(..), CInt(..))
241import Foreign.Ptr (plusPtr, minusPtr, nullPtr)
241import Foreign.Ptr (plusPtr, minusPtr, nullPtr)
242−import Streamly.Internal.Data.Unbox
242+import Streamly.Internal.Data.MutByteArray
243 ( MutByteArray(..)
243 ( MutByteArray(..)
244 , MutableByteArray
244 , MutableByteArray
245− , Unbox(..)
246 , PinnedState(..)
245 , PinnedState(..)
247 , getMutableByteArray#
246 , getMutableByteArray#
248 , putSliceUnsafe
247 , putSliceUnsafe
249 )
248 )
249+import Streamly.Internal.Data.Unbox (Unbox(..))
250import GHC.Base
250import GHC.Base
251 ( IO(..)
251 ( IO(..)
252 , Int(..)
252 , Int(..)
@@ -266,11 +266,11 @@ import Streamly.Internal.Data.Unfold.Type (Unfold(..))
266import Streamly.Internal.System.IO (arrayPayloadSize, defaultChunkSize)
266import Streamly.Internal.System.IO (arrayPayloadSize, defaultChunkSize)
267
267
268import qualified Streamly.Internal.Data.Fold.Type as FL
268import qualified Streamly.Internal.Data.Fold.Type as FL
269+import qualified Streamly.Internal.Data.MutByteArray as Unboxed
269import qualified Streamly.Internal.Data.Producer as Producer
270import qualified Streamly.Internal.Data.Producer as Producer
270import qualified Streamly.Internal.Data.Stream.Type as D
271import qualified Streamly.Internal.Data.Stream.Type as D
271import qualified Streamly.Internal.Data.Stream.Lift as D
272import qualified Streamly.Internal.Data.Stream.Lift as D
272import qualified Streamly.Internal.Data.StreamK.Type as K
273import qualified Streamly.Internal.Data.StreamK.Type as K
273−import qualified Streamly.Internal.Data.Unbox as Unboxed
274import qualified Prelude
274import qualified Prelude
275
275
276import Prelude hiding
276import Prelude hiding
core/src/Streamly/Internal/Data/MutByteArray.hsnew file+249
@@ -0,0 +1,249 @@
1+{-# LANGUAGE UnboxedTuples #-}
2+
3+-- |
4+-- Module : Streamly.Internal.Data.MutByteArray
5+-- Copyright : (c) 2023 Composewell Technologies
6+-- License : BSD3-3-Clause
7+-- Maintainer : streamly@composewell.com
8+-- Stability : experimental
9+-- Portability : GHC
10+--
11+module Streamly.Internal.Data.MutByteArray
12+ (
13+ -- ** MutByteArray
14+ MutByteArray(..)
15+ , MutableByteArray
16+ , getMutableByteArray#
17+
18+ -- ** Pinning
19+ , PinnedState(..)
20+ , isPinned
21+ , pin
22+ , unpin
23+
24+ -- ** Allocation
25+ , nil
26+ , newBytesAs
27+ , newByteArray
28+ , pinnedNewByteArray
29+ , pinnedNewAlignedBytes
30+
31+ -- ** Access
32+ , sizeOfMutableByteArray
33+ , putSliceUnsafe
34+ , asPtrUnsafe
35+ ) where
36+
37+import Control.Monad.IO.Class (MonadIO(..))
38+#ifdef DEBUG
39+import Debug.Trace (trace)
40+#endif
41+import GHC.Base (IO(..))
42+import System.IO.Unsafe (unsafePerformIO)
43+
44+import GHC.Exts
45+
46+--------------------------------------------------------------------------------
47+-- The ArrayContents type
48+--------------------------------------------------------------------------------
49+
50+data PinnedState
51+ = Pinned
52+ | Unpinned
53+
54+-- XXX can use UnliftedNewtypes
55+
56+-- | A lifted mutable byte array type wrapping @MutableByteArray# RealWorld@.
57+-- This is a low level array used to back high level unboxed arrays and
58+-- serialized data.
59+data MutByteArray = MutByteArray (MutableByteArray# RealWorld)
60+
61+{-# DEPRECATED MutableByteArray "Please use MutByteArray instead" #-}
62+type MutableByteArray = MutByteArray
63+
64+{-# INLINE getMutableByteArray# #-}
65+getMutableByteArray# :: MutByteArray -> MutableByteArray# RealWorld
66+getMutableByteArray# (MutByteArray mbarr) = mbarr
67+
68+-- | Return the size of the array in bytes.
69+{-# INLINE sizeOfMutableByteArray #-}
70+sizeOfMutableByteArray :: MutByteArray -> IO Int
71+sizeOfMutableByteArray (MutByteArray arr) =
72+ IO $ \s ->
73+ case getSizeofMutableByteArray# arr s of
74+ (# s1, i #) -> (# s1, I# i #)
75+
76+{-# INLINE touch #-}
77+touch :: MutByteArray -> IO ()
78+touch (MutByteArray contents) =
79+ IO $ \s -> case touch# contents s of s' -> (# s', () #)
80+
81+-- XXX We can provide another API for "unsafe" FFI calls passing an unlifted
82+-- pointer to the FFI call. For unsafe calls we do not need to pin the array.
83+-- We can pass an unlifted pointer to the FFI routine to avoid GC kicking in
84+-- before the pointer is wrapped.
85+--
86+-- From the GHC manual:
87+--
88+-- GHC, since version 8.4, guarantees that garbage collection will never occur
89+-- during an unsafe call, even in the bytecode interpreter, and further
90+-- guarantees that unsafe calls will be performed in the calling thread. Making
91+-- it safe to pass heap-allocated objects to unsafe functions.
92+
93+-- | Use a @MutByteArray@ as @Ptr a@. This is useful when we want to pass
94+-- an array as a pointer to some operating system call or to a "safe" FFI call.
95+--
96+-- If the array is not pinned it is copied to pinned memory before passing it
97+-- to the monadic action.
98+--
99+-- /Performance Notes:/ Forces a copy if the array is not pinned. It is advised
100+-- that the programmer keeps this in mind and creates a pinned array
101+-- opportunistically before this operation occurs, to avoid the cost of a copy
102+-- if possible.
103+--
104+-- /Unsafe/ because of direct pointer operations. The user must ensure that
105+-- they are writing within the legal bounds of the array.
106+--
107+-- /Pre-release/
108+--
109+{-# INLINE asPtrUnsafe #-}
110+asPtrUnsafe :: MonadIO m => MutByteArray -> (Ptr a -> m b) -> m b
111+asPtrUnsafe arr f = do
112+ contents <- liftIO $ pin arr
113+ let !ptr = Ptr (byteArrayContents#
114+ (unsafeCoerce# (getMutableByteArray# contents)))
115+ r <- f ptr
116+ liftIO $ touch contents
117+ return r
118+
119+--------------------------------------------------------------------------------
120+-- Creation
121+--------------------------------------------------------------------------------
122+
123+{-# NOINLINE nil #-}
124+nil :: MutByteArray
125+nil = unsafePerformIO $ newByteArray 0
126+
127+{-# INLINE newByteArray #-}
128+newByteArray :: Int -> IO MutByteArray
129+newByteArray nbytes | nbytes < 0 =
130+ errorWithoutStackTrace "newByteArray: size must be >= 0"
131+newByteArray (I# nbytes) = IO $ \s ->
132+ case newByteArray# nbytes s of
133+ (# s', mbarr# #) ->
134+ let c = MutByteArray mbarr#
135+ in (# s', c #)
136+
137+{-# INLINE pinnedNewByteArray #-}
138+pinnedNewByteArray :: Int -> IO MutByteArray
139+pinnedNewByteArray nbytes | nbytes < 0 =
140+ errorWithoutStackTrace "pinnedNewByteArray: size must be >= 0"
141+pinnedNewByteArray (I# nbytes) = IO $ \s ->
142+ case newPinnedByteArray# nbytes s of
143+ (# s', mbarr# #) ->
144+ let c = MutByteArray mbarr#
145+ in (# s', c #)
146+
147+{-# INLINE pinnedNewAlignedBytes #-}
148+pinnedNewAlignedBytes :: Int -> Int -> IO MutByteArray
149+pinnedNewAlignedBytes nbytes _align | nbytes < 0 =
150+ errorWithoutStackTrace "pinnedNewAlignedBytes: size must be >= 0"
151+pinnedNewAlignedBytes (I# nbytes) (I# align) = IO $ \s ->
152+ case newAlignedPinnedByteArray# nbytes align s of
153+ (# s', mbarr# #) ->
154+ let c = MutByteArray mbarr#
155+ in (# s', c #)
156+
157+{-# INLINE newBytesAs #-}
158+newBytesAs :: PinnedState -> Int -> IO MutByteArray
159+newBytesAs Unpinned = newByteArray
160+newBytesAs Pinned = pinnedNewByteArray
161+
162+-------------------------------------------------------------------------------
163+-- Copying
164+-------------------------------------------------------------------------------
165+
166+-- | Put a sub range of a source array into a subrange of a destination array.
167+-- This is not safe as it does not check the bounds.
168+{-# INLINE putSliceUnsafe #-}
169+putSliceUnsafe ::
170+ MonadIO m
171+ => MutByteArray
172+ -> Int
173+ -> MutByteArray
174+ -> Int
175+ -> Int
176+ -> m ()
177+putSliceUnsafe src srcStartBytes dst dstStartBytes lenBytes = liftIO $ do
178+#ifdef DEBUG
179+ srcLen <- sizeOfMutableByteArray src
180+ dstLen <- sizeOfMutableByteArray src
181+ when (srcLen - srcStartBytes < lenBytes) $ error "SRC: Insufficient length."
182+ when (dstLen - dstStartBytes < lenBytes) $ error "DST: Insufficient length."
183+#endif
184+ let !(I# srcStartBytes#) = srcStartBytes
185+ !(I# dstStartBytes#) = dstStartBytes
186+ !(I# lenBytes#) = lenBytes
187+ let arrS# = getMutableByteArray# src
188+ arrD# = getMutableByteArray# dst
189+ IO $ \s# -> (# copyMutableByteArray#
190+ arrS# srcStartBytes# arrD# dstStartBytes# lenBytes# s#
191+ , () #)
192+
193+-------------------------------------------------------------------------------
194+-- Pinning & Unpinning
195+-------------------------------------------------------------------------------
196+
197+{-# INLINE isPinned #-}
198+isPinned :: MutByteArray -> Bool
199+isPinned (MutByteArray arr#) =
200+ let pinnedInt = I# (isMutableByteArrayPinned# arr#)
201+ in pinnedInt /= 0
202+
203+
204+{-# INLINE cloneMutableArrayWith# #-}
205+cloneMutableArrayWith#
206+ :: (Int# -> State# RealWorld -> (# State# RealWorld
207+ , MutableByteArray# RealWorld #))
208+ -> MutableByteArray# RealWorld
209+ -> State# RealWorld
210+ -> (# State# RealWorld, MutableByteArray# RealWorld #)
211+cloneMutableArrayWith# alloc# arr# s# =
212+ case getSizeofMutableByteArray# arr# s# of
213+ (# s1#, i# #) ->
214+ case alloc# i# s1# of
215+ (# s2#, arr1# #) ->
216+ case copyMutableByteArray# arr# 0# arr1# 0# i# s2# of
217+ s3# -> (# s3#, arr1# #)
218+
219+{-# INLINE pin #-}
220+pin :: MutByteArray -> IO MutByteArray
221+pin arr@(MutByteArray marr#) =
222+ if isPinned arr
223+ then return arr
224+ else
225+#ifdef DEBUG
226+ do
227+ -- XXX dump stack trace
228+ trace ("pin: Copying array") (return ())
229+#endif
230+ IO
231+ $ \s# ->
232+ case cloneMutableArrayWith# newPinnedByteArray# marr# s# of
233+ (# s1#, marr1# #) -> (# s1#, MutByteArray marr1# #)
234+
235+{-# INLINE unpin #-}
236+unpin :: MutByteArray -> IO MutByteArray
237+unpin arr@(MutByteArray marr#) =
238+ if not (isPinned arr)
239+ then return arr
240+ else
241+#ifdef DEBUG
242+ do
243+ -- XXX dump stack trace
244+ trace ("unpin: Copying array") (return ())
245+#endif
246+ IO
247+ $ \s# ->
248+ case cloneMutableArrayWith# newByteArray# marr# s# of
249+ (# s1#, marr1# #) -> (# s1#, MutByteArray marr1# #)
core/src/Streamly/Internal/Data/Serialize.hs+4−1
@@ -13,8 +13,10 @@
13
13
14module Streamly.Internal.Data.Serialize
14module Streamly.Internal.Data.Serialize
15 (
15 (
16+ -- * MutByteArray
17+ module Streamly.Internal.Data.MutByteArray
16 -- * Unbox
18 -- * Unbox
17− module Streamly.Internal.Data.Unbox
19+ , module Streamly.Internal.Data.Unbox
18 , module Streamly.Internal.Data.Unbox.TH
20 , module Streamly.Internal.Data.Unbox.TH
19 -- * Serialize
21 -- * Serialize
20 , module Streamly.Internal.Data.Serialize.Type
22 , module Streamly.Internal.Data.Serialize.Type
@@ -37,6 +39,7 @@ import GHC.Num.Integer (Integer(..))
37import GHC.Integer.GMP.Internals (Integer(..), BigNat(..))
39import GHC.Integer.GMP.Internals (Integer(..), BigNat(..))
38#endif
40#endif
39
41
42+import Streamly.Internal.Data.MutByteArray
40import Streamly.Internal.Data.Serialize.TH
43import Streamly.Internal.Data.Serialize.TH
41import Streamly.Internal.Data.Serialize.Type
44import Streamly.Internal.Data.Serialize.Type
42import Streamly.Internal.Data.Unbox
45import Streamly.Internal.Data.Unbox
core/src/Streamly/Internal/Data/Serialize/TH/RecHeader.hs+1−1
@@ -27,7 +27,7 @@ import Data.Maybe (fromJust)
27import Language.Haskell.TH
27import Language.Haskell.TH
28import Streamly.Internal.Data.Serialize.Type (Serialize(..))
28import Streamly.Internal.Data.Serialize.Type (Serialize(..))
29import Data.Foldable (foldlM)
29import Data.Foldable (foldlM)
30−import Streamly.Internal.Data.Unbox (MutByteArray)
30+import Streamly.Internal.Data.MutByteArray (MutByteArray)
31import Data.Proxy (Proxy(..))
31import Data.Proxy (Proxy(..))
32
32
33import qualified Streamly.Internal.Data.Unbox as Unbox
33import qualified Streamly.Internal.Data.Unbox as Unbox
core/src/Streamly/Internal/Data/Serialize/Type.hs+5−7
@@ -27,17 +27,15 @@ import Control.Exception (assert)
27
27
28import Data.List (foldl')
28import Data.List (foldl')
29import Data.Proxy (Proxy (..))
29import Data.Proxy (Proxy (..))
30−import Streamly.Internal.Data.Unbox
30+import Streamly.Internal.Data.Unbox (Unbox)
31− ( MutByteArray(..)
31+import Streamly.Internal.Data.MutByteArray (MutByteArray(..), PinnedState(..))
32− , PinnedState(..)
33− , Unbox
34− )
35import Streamly.Internal.Data.Array.Type (Array(..))
32import Streamly.Internal.Data.Array.Type (Array(..))
36import Streamly.Internal.System.IO (unsafeInlineIO)
33import Streamly.Internal.System.IO (unsafeInlineIO)
37import GHC.Int (Int16(..), Int32(..), Int64(..), Int8(..))
34import GHC.Int (Int16(..), Int32(..), Int64(..), Int8(..))
38import GHC.Word (Word16(..), Word32(..), Word64(..), Word8(..))
35import GHC.Word (Word16(..), Word32(..), Word64(..), Word8(..))
39import GHC.Stable (StablePtr(..))
36import GHC.Stable (StablePtr(..))
40
37
38+import qualified Streamly.Internal.Data.MutByteArray as MBA
41import qualified Streamly.Internal.Data.Unbox as Unbox
39import qualified Streamly.Internal.Data.Unbox as Unbox
42import qualified Streamly.Internal.Data.Array as Array
40import qualified Streamly.Internal.Data.Array as Array
43import qualified Streamly.Internal.Data.MutArray as MutArray
41import qualified Streamly.Internal.Data.MutArray as MutArray
@@ -297,7 +295,7 @@ instance Serialize (Array a) where
297 serialize off arr (Array {..}) = do
295 serialize off arr (Array {..}) = do
298 let arrLen = arrEnd - arrStart
296 let arrLen = arrEnd - arrStart
299 off1 <- serialize off arr arrLen
297 off1 <- serialize off arr arrLen
300− Unbox.putSliceUnsafe arrContents arrStart arr off1 arrLen
298+ MBA.putSliceUnsafe arrContents arrStart arr off1 arrLen
301 pure (off1 + arrLen)
299 pure (off1 + arrLen)
302
300
303instance (Serialize a, Serialize b) => Serialize (a, b) where
301instance (Serialize a, Serialize b) => Serialize (a, b) where
@@ -325,7 +323,7 @@ encodeAs :: forall a. Serialize a => PinnedState -> a -> Array Word8
325encodeAs ps a =
323encodeAs ps a =
326 unsafeInlineIO $ do
324 unsafeInlineIO $ do
327 let len = size 0 a
325 let len = size 0 a
328− mbarr <- Unbox.newBytesAs ps len
326+ mbarr <- MBA.newBytesAs ps len
329 off <- serialize 0 mbarr a
327 off <- serialize 0 mbarr a
330 assertM(len == off)
328 assertM(len == off)
331 pure $ Array mbarr 0 off
329 pure $ Array mbarr 0 off
core/src/Streamly/Internal/Data/Unbox.hs+2−226
@@ -13,27 +13,8 @@
13--
13--
14module Streamly.Internal.Data.Unbox
14module Streamly.Internal.Data.Unbox
15 (
15 (
16− -- ** MutByteArray
17− MutByteArray(..)
18− , MutableByteArray
19− , getMutableByteArray#
20− , sizeOfMutableByteArray
21− , nil
22− , putSliceUnsafe
23− , asPtrUnsafe
24−
25− -- ** Allocation
26− , PinnedState(..)
27− , isPinned
28− , pin
29− , unpin
30− , newBytesAs
31− , newByteArray
32− , pinnedNewByteArray
33− , pinnedNewAlignedBytes
34−
35 -- ** Unbox type class
16 -- ** Unbox type class
36− , Unbox(..)
17+ Unbox(..)
37
18
38 -- ** Peek and poke utilities
19 -- ** Peek and poke utilities
39 , BoundedPtr (..)
20 , BoundedPtr (..)
@@ -59,7 +40,6 @@ module Streamly.Internal.Data.Unbox
59#include "MachDeps.h"
40#include "MachDeps.h"
60#include "ArrayMacros.h"
41#include "ArrayMacros.h"
61
42
62−import Control.Monad.IO.Class (MonadIO(..))
63import Control.Monad (void, when)
43import Control.Monad (void, when)
64import Data.Complex (Complex((:+)))
44import Data.Complex (Complex((:+)))
65import Data.Functor ((<&>))
45import Data.Functor ((<&>))
@@ -81,217 +61,13 @@ import GHC.Word (Word16(..), Word32(..), Word64(..), Word8(..))
81import GHC.RTS.Flags (IoSubSystem(..))
61import GHC.RTS.Flags (IoSubSystem(..))
82#endif
62#endif
83import Streamly.Internal.Data.Builder (Builder (..))
63import Streamly.Internal.Data.Builder (Builder (..))
84−import System.IO.Unsafe (unsafePerformIO)
85
64
86import GHC.Generics
65import GHC.Generics
87import GHC.Exts
66import GHC.Exts
88import GHC.TypeLits
67import GHC.TypeLits
89import Prelude hiding (read)
68import Prelude hiding (read)
90
69
91−--------------------------------------------------------------------------------
70+import Streamly.Internal.Data.MutByteArray (MutByteArray(..))
92−-- The ArrayContents type
93−--------------------------------------------------------------------------------
94−
95−data PinnedState
96− = Pinned
97− | Unpinned
98−
99−-- XXX can use UnliftedNewtypes
100−
101−-- | A lifted mutable byte array type wrapping @MutableByteArray# RealWorld@.
102−-- This is a low level array used to back high level unboxed arrays and
103−-- serialized data.
104−data MutByteArray = MutByteArray (MutableByteArray# RealWorld)
105−
106−{-# DEPRECATED MutableByteArray "Please use MutByteArray instead" #-}
107−type MutableByteArray = MutByteArray
108−
109−{-# INLINE getMutableByteArray# #-}
110−getMutableByteArray# :: MutByteArray -> MutableByteArray# RealWorld
111−getMutableByteArray# (MutByteArray mbarr) = mbarr
112−
113−-- | Return the size of the array in bytes.
114−{-# INLINE sizeOfMutableByteArray #-}
115−sizeOfMutableByteArray :: MutByteArray -> IO Int
116−sizeOfMutableByteArray (MutByteArray arr) =
117− IO $ \s ->
118− case getSizeofMutableByteArray# arr s of
119− (# s1, i #) -> (# s1, I# i #)
120−
121−{-# INLINE touch #-}
122−touch :: MutByteArray -> IO ()
123−touch (MutByteArray contents) =
124− IO $ \s -> case touch# contents s of s' -> (# s', () #)
125−
126−-- XXX We can provide another API for "unsafe" FFI calls passing an unlifted
127−-- pointer to the FFI call. For unsafe calls we do not need to pin the array.
128−-- We can pass an unlifted pointer to the FFI routine to avoid GC kicking in
129−-- before the pointer is wrapped.
130−--
131−-- From the GHC manual:
132−--
133−-- GHC, since version 8.4, guarantees that garbage collection will never occur
134−-- during an unsafe call, even in the bytecode interpreter, and further
135−-- guarantees that unsafe calls will be performed in the calling thread. Making
136−-- it safe to pass heap-allocated objects to unsafe functions.
137−
138−-- | Use a @MutByteArray@ as @Ptr a@. This is useful when we want to pass
139−-- an array as a pointer to some operating system call or to a "safe" FFI call.
140−--
141−-- If the array is not pinned it is copied to pinned memory before passing it
142−-- to the monadic action.
143−--
144−-- /Performance Notes:/ Forces a copy if the array is not pinned. It is advised
145−-- that the programmer keeps this in mind and creates a pinned array
146−-- opportunistically before this operation occurs, to avoid the cost of a copy
147−-- if possible.
148−--
149−-- /Unsafe/ because of direct pointer operations. The user must ensure that
150−-- they are writing within the legal bounds of the array.
151−--
152−-- /Pre-release/
153−--
154−{-# INLINE asPtrUnsafe #-}
155−asPtrUnsafe :: MonadIO m => MutByteArray -> (Ptr a -> m b) -> m b
156−asPtrUnsafe arr f = do
157− contents <- liftIO $ pin arr
158− let !ptr = Ptr (byteArrayContents#
159− (unsafeCoerce# (getMutableByteArray# contents)))
160− r <- f ptr
161− liftIO $ touch contents
162− return r
163−
164−--------------------------------------------------------------------------------
165−-- Creation
166−--------------------------------------------------------------------------------
167−
168−{-# NOINLINE nil #-}
169−nil :: MutByteArray
170−nil = unsafePerformIO $ newByteArray 0
171−
172−{-# INLINE newByteArray #-}
173−newByteArray :: Int -> IO MutByteArray
174−newByteArray nbytes | nbytes < 0 =
175− errorWithoutStackTrace "newByteArray: size must be >= 0"
176−newByteArray (I# nbytes) = IO $ \s ->
177− case newByteArray# nbytes s of
178− (# s', mbarr# #) ->
179− let c = MutByteArray mbarr#
180− in (# s', c #)
181−
182−{-# INLINE pinnedNewByteArray #-}
183−pinnedNewByteArray :: Int -> IO MutByteArray
184−pinnedNewByteArray nbytes | nbytes < 0 =
185− errorWithoutStackTrace "pinnedNewByteArray: size must be >= 0"
186−pinnedNewByteArray (I# nbytes) = IO $ \s ->
187− case newPinnedByteArray# nbytes s of
188− (# s', mbarr# #) ->
189− let c = MutByteArray mbarr#
190− in (# s', c #)
191−
192−{-# INLINE pinnedNewAlignedBytes #-}
193−pinnedNewAlignedBytes :: Int -> Int -> IO MutByteArray
194−pinnedNewAlignedBytes nbytes _align | nbytes < 0 =
195− errorWithoutStackTrace "pinnedNewAlignedBytes: size must be >= 0"
196−pinnedNewAlignedBytes (I# nbytes) (I# align) = IO $ \s ->
197− case newAlignedPinnedByteArray# nbytes align s of
198− (# s', mbarr# #) ->
199− let c = MutByteArray mbarr#
200− in (# s', c #)
201−
202−{-# INLINE newBytesAs #-}
203−newBytesAs :: PinnedState -> Int -> IO MutByteArray
204−newBytesAs Unpinned = newByteArray
205−newBytesAs Pinned = pinnedNewByteArray
206−
207−-------------------------------------------------------------------------------
208−-- Copying
209−-------------------------------------------------------------------------------
210−
211−-- | Put a sub range of a source array into a subrange of a destination array.
212−-- This is not safe as it does not check the bounds.
213−{-# INLINE putSliceUnsafe #-}
214−putSliceUnsafe ::
215− MonadIO m
216− => MutByteArray
217− -> Int
218− -> MutByteArray
219− -> Int
220− -> Int
221− -> m ()
222−putSliceUnsafe src srcStartBytes dst dstStartBytes lenBytes = liftIO $ do
223−#ifdef DEBUG
224− srcLen <- sizeOfMutableByteArray src
225− dstLen <- sizeOfMutableByteArray src
226− when (srcLen - srcStartBytes < lenBytes) $ error "SRC: Insufficient length."
227− when (dstLen - dstStartBytes < lenBytes) $ error "DST: Insufficient length."
228−#endif
229− let !(I# srcStartBytes#) = srcStartBytes
230− !(I# dstStartBytes#) = dstStartBytes
231− !(I# lenBytes#) = lenBytes
232− let arrS# = getMutableByteArray# src
233− arrD# = getMutableByteArray# dst
234− IO $ \s# -> (# copyMutableByteArray#
235− arrS# srcStartBytes# arrD# dstStartBytes# lenBytes# s#
236− , () #)
237−
238−-------------------------------------------------------------------------------
239−-- Pinning & Unpinning
240−-------------------------------------------------------------------------------
241−
242−{-# INLINE isPinned #-}
243−isPinned :: MutByteArray -> Bool
244−isPinned (MutByteArray arr#) =
245− let pinnedInt = I# (isMutableByteArrayPinned# arr#)
246− in pinnedInt /= 0
247−
248−
249−{-# INLINE cloneMutableArrayWith# #-}
250−cloneMutableArrayWith#
251− :: (Int# -> State# RealWorld -> (# State# RealWorld
252− , MutableByteArray# RealWorld #))
253− -> MutableByteArray# RealWorld
254− -> State# RealWorld
255− -> (# State# RealWorld, MutableByteArray# RealWorld #)
256−cloneMutableArrayWith# alloc# arr# s# =
257− case getSizeofMutableByteArray# arr# s# of
258− (# s1#, i# #) ->
259− case alloc# i# s1# of
260− (# s2#, arr1# #) ->
261− case copyMutableByteArray# arr# 0# arr1# 0# i# s2# of
262− s3# -> (# s3#, arr1# #)
263−
264−{-# INLINE pin #-}
265−pin :: MutByteArray -> IO MutByteArray
266−pin arr@(MutByteArray marr#) =
267− if isPinned arr
268− then return arr
269− else
270−#ifdef DEBUG
271− do
272− -- XXX dump stack trace
273− trace ("pin: Copying array") (return ())
274−#endif
275− IO
276− $ \s# ->
277− case cloneMutableArrayWith# newPinnedByteArray# marr# s# of
278− (# s1#, marr1# #) -> (# s1#, MutByteArray marr1# #)
279−
280−{-# INLINE unpin #-}
281−unpin :: MutByteArray -> IO MutByteArray
282−unpin arr@(MutByteArray marr#) =
283− if not (isPinned arr)
284− then return arr
285− else
286−#ifdef DEBUG
287− do
288− -- XXX dump stack trace
289− trace ("unpin: Copying array") (return ())
290−#endif
291− IO
292− $ \s# ->
293− case cloneMutableArrayWith# newByteArray# marr# s# of
294− (# s1#, marr1# #) -> (# s1#, MutByteArray marr1# #)
295
71
296--------------------------------------------------------------------------------
72--------------------------------------------------------------------------------
297-- The Unbox type class
73-- The Unbox type class
core/streamly-core.cabal+1
@@ -421,6 +421,7 @@ library
421 , Streamly.Internal.Data.Array.Type
421 , Streamly.Internal.Data.Array.Type
422
422
423 -- Unboxed IORef
423 -- Unboxed IORef
424+ , Streamly.Internal.Data.MutByteArray
424 , Streamly.Internal.Data.Unbox
425 , Streamly.Internal.Data.Unbox
425 , Streamly.Internal.Data.IORef.Unboxed
426 , Streamly.Internal.Data.IORef.Unboxed
426 , Streamly.Internal.Data.Unbox.TH
427 , Streamly.Internal.Data.Unbox.TH