on master help sign in
Rename, update docs of array creation from ptr

Rename fromString to fromCString to avoid confusion. fromString sounds like it creates an array of Char from a list of Char. CString is more precise definition of a nul terminated byte string. Also, add fromPtr to create an array from a pointer type.

commitcc072be34d6ea73acbf0af2406c5c67f48ffa45c authorHarendra Kumar <harendra@composewell.com> dateSat 15 Aug 2020, 20:07 (6 years ago) parentead1601
2 files changed+56−44
src/Streamly/Internal/Memory/Array.hs+5−2 src/Streamly/Internal/Memory/Array/Types.hs+51−42
src/Streamly/Internal/Memory/Array.hs+5−2
@@ -40,9 +40,12 @@ module Streamly.Internal.Memory.Array
4040
4141 -- * Construction
4242
43− -- Foreign (Unsafe)
43+ -- Pure, From Static Memory (Unsafe)
44+ -- We can use fromPtrM#, fromCStringM# and fromAddrM# to create arrays from
45+ -- a dynamic memory address which requires a finalizer.
46+ , A.fromPtr
4447 , A.fromAddr#
45− , A.fromString#
48+ , A.fromCString#
4649
4750 -- Pure List APIs
4851 , A.fromListN
src/Streamly/Internal/Memory/Array/Types.hs+51−42
@@ -21,8 +21,9 @@ module Streamly.Internal.Memory.Array.Types
2121 -- * Construction
2222 , spliceTwo
2323
24+ , fromPtr
2425 , fromAddr#
25− , fromString#
26+ , fromCString#
2627 , fromList
2728 , fromListN
2829 , fromStreamDN
@@ -86,7 +87,6 @@ import Control.Monad.IO.Class (MonadIO(..))
8687import Data.Word (Word8)
8788import Foreign.C.String (CString)
8889import Foreign.C.Types (CSize(..))
89−import Foreign.ForeignPtr.Unsafe (unsafeForeignPtrToPtr)
9090import Foreign.Ptr (plusPtr, castPtr)
9191import Foreign.Storable (Storable(..))
9292import GHC.Base (Addr#, nullAddr#)
@@ -217,6 +217,30 @@ spliceTwo :: (MonadIO m, Storable a) => Array a -> Array a -> m (Array a)
217217spliceTwo arr1 arr2 =
218218 unsafeFreeze <$> MA.spliceTwo (unsafeThaw arr1) (unsafeThaw arr2)
219219
220+-- | Create an 'Array' of the given number of elements of type @a@ from a read
221+-- only pointer @Ptr a@. The pointer is not freed when the array is garbage
222+-- collected. This API is unsafe for the following reasons:
223+--
224+-- 1. The pointer must point to static pinned memory or foreign memory that
225+-- does not require freeing..
226+-- 2. The pointer must be legally accessible upto the given length.
227+-- 3. To guarantee that the array is immutable, the contents of the address
228+-- must be guaranteed to not change.
229+--
230+-- /Unsafe/
231+--
232+-- /Internal/
233+--
234+{-# INLINE fromPtr #-}
235+fromPtr :: Int -> Ptr a -> Array a
236+fromPtr n ptr = MA.unsafeInlineIO $ do
237+ fptr <- newForeignPtr_ ptr
238+ let end = ptr `plusPtr` n
239+ return $ Array
240+ { aStart = fptr
241+ , aEnd = end
242+ }
243+
220244-- XXX when converting an array of Word8 from a literal string we can simply
221245-- refer to the literal string. Is it possible to write rules such that
222246-- fromList Word8 can be rewritten so that GHC does not first convert the
@@ -227,13 +251,8 @@ spliceTwo arr1 arr2 =
227251-- an array of the required type. With template Haskell we can provide a safe
228252-- version of fromString#.
229253--
230−-- | Create an @Array Word8@ of the given length from a machine address
231−-- 'Addr#'. This API is unsafe for the following reasons:
232−--
233−-- 1. The address must point to pinned memory or foreign memory.
234−-- 2. The address must be legally accessible upto the given length.
235−-- 3. To guarantee that the array is immutable, the contents of the address
236−-- must be guaranteed to not change.
254+-- | Create an @Array Word8@ of the given length from a static, read only
255+-- machine address 'Addr#'. See 'fromPtr' for safety caveats.
237256--
238257-- A common use case for this API is to create an array from a static unboxed
239258-- string literal. GHC string literals are of type 'Addr#', and must contain
@@ -252,52 +271,42 @@ spliceTwo arr1 arr2 =
252271--
253272-- /Time complexity: O(1)/
254273--
274+-- /Internal/
275+--
255276{-# INLINE fromAddr# #-}
256−fromAddr# :: Int -> Addr# -> IO (Array Word8)
257−fromAddr# n addr# = do
258− ptr <- newForeignPtr_ (castPtr $ Ptr addr#)
259− let p = unsafeForeignPtrToPtr ptr
260− let end = p `plusPtr` n
261− return $ Array
262− { aStart = ptr
263− , aEnd = end
264− }
277+fromAddr# :: Int -> Addr# -> Array a
278+fromAddr# n addr# = fromPtr n (castPtr $ Ptr addr#)
265279
266−-- | Like 'fromAddr#' but determines the length of the array upto and excluding
267−-- the first @0@ byte. The address must be legally accessible up to the first
268−-- NUL byte.
280+-- | Generate a byte array from an 'Addr#' that contains a sequence of NUL
281+-- (@0@) terminated bytes. The array would not include the NUL byte. The
282+-- address must be in static read-only memory and must be legally accessible up
283+-- to and including the first NUL byte.
269284--
270−-- A common use case for this API is to create an array from an unboxed string
271−-- literal. Unboxed string literals are guaranteed to be terminated by a NUL
272−-- byte.
285+-- An unboxed string literal (e.g. @"hello"#@) is a common example of an
286+-- 'Addr#' in static read only memory. It represents the UTF8 encoded sequence
287+-- of bytes terminated by a NUL byte (a 'CString') corresponding to the
288+-- given unicode string.
273289--
274−-- >>> fromString# "hello world!"#
290+-- >>> fromCString# "hello world!"#
275291-- > [104,101,108,108,111,32,119,111,114,108,100,33]
276292--
277−-- >>> fromString# "\255\NUL\255"#
293+-- >>> fromCString# "\255\NUL\255"#
278294-- > [255]
279295--
280−-- /See also: 'fromAddr#', 'fromString'/
296+-- /See also: 'fromAddr#'/
281297--
282298-- /Unsafe/
283299--
284300-- /Time complexity: O(n) (computes the length of the string)/
285301--
286−{-# INLINE fromString# #-}
287−fromString# :: Addr# -> IO (Array Word8)
288−fromString# addr# = do
289− ptr <- newForeignPtr_ (castPtr cstr)
290− len <- c_strlen cstr
291− let n = fromIntegral len
292− let p = unsafeForeignPtrToPtr ptr
293− let end = p `plusPtr` n
294− return $ Array
295− { aStart = ptr
296− , aEnd = end
297− }
298− where
299− cstr :: CString
300− cstr = Ptr addr#
302+-- /Internal/
303+--
304+{-# INLINE fromCString# #-}
305+fromCString# :: Addr# -> Array Word8
306+fromCString# addr# = do
307+ let cstr = Ptr addr#
308+ len = MA.unsafeInlineIO $ c_strlen cstr
309+ fromPtr (fromIntegral len) (castPtr cstr)
301310
302311-- | Create an 'Array' from the first N elements of a list. The array is
303312-- allocated to size N, if the list terminates before N elements then the