[project @ 2002-09-06 14:08:45 by simonmar]
authorsimonmar <unknown>
Fri, 6 Sep 2002 14:08:45 +0000 (14:08 +0000)
committersimonmar <unknown>
Fri, 6 Sep 2002 14:08:45 +0000 (14:08 +0000)
Implement

   mallocForeignPtr :: Storable a => IO (ForeignPtr a)
   mallocForeignPtrBytes :: Int -> IO (ForeignPtr a)

as GHC extensions for the time being.  I strongly recommend using
these if you need some garbage-collected memory to pass to a foreign
function.

Foreign/ForeignPtr.hs

index 6b3fb88..586cd4f 100644 (file)
@@ -25,10 +25,15 @@ module Foreign.ForeignPtr
        , foreignPtrToPtr        -- :: ForeignPtr a -> Ptr a
        , touchForeignPtr        -- :: ForeignPtr a -> IO ()
        , castForeignPtr         -- :: ForeignPtr a -> ForeignPtr b
+
+       -- * GHC extensions
+       , mallocForeignPtr      --  :: Storable a => IO (ForeignPtr a)
+       , mallocForeignPtrBytes --  :: Int -> IO (ForeignPtr a)
         ) 
        where
 
 import Foreign.Ptr
+import Foreign.Storable
 import Data.Dynamic
 
 #ifdef __GLASGOW_HASKELL__
@@ -59,16 +64,17 @@ INSTANCE_TYPEABLE1(ForeignPtr,foreignPtrTc,"ForeignPtr")
 -- type argument of 'ForeignPtr' should normally be an instance of
 -- class 'Storable'.
 --
-data ForeignPtr a = ForeignPtr ForeignObj#
-
-instance CCallable (ForeignPtr a)
+data ForeignPtr a 
+  = ForeignPtr ForeignObj#
+  | MallocPtr  (MutableByteArray# RealWorld)
 
 eqForeignPtr  :: ForeignPtr a -> ForeignPtr a -> Bool
 eqForeignPtr (ForeignPtr fo1#) (ForeignPtr fo2#) = eqForeignObj# fo1# fo2#
+eqForeignPtr (MallocPtr fo1#)  (MallocPtr fo2#)  = sameMutableByteArray# fo1# fo2#
+eqForeignPtr _ _ = False
 
 instance Eq (ForeignPtr a) where 
     p == q = eqForeignPtr p q
-    p /= q = not (eqForeignPtr p q)
 
 newForeignPtr :: Ptr a -> IO () -> IO (ForeignPtr a)
 -- ^Turns a plain memory reference into a foreign object
@@ -85,12 +91,42 @@ newForeignPtr p finalizer
        addForeignPtrFinalizer fObj finalizer
        return fObj
 
+-- | allocates some memory and returns a ForeignPtr to it.  The memory
+-- will be released automatically when the ForeignPtr is discarded.
+--
+-- @mallocForeignPtr@ is equivalent to
+--
+-- >    do { p <- malloc; newForeignPtr p free }
+-- 
+-- although it may be implemented differently internally.  You may not
+-- assume that the memory returned by 'mallocForeignPtr' has been
+-- allocated with C's @malloc()@.
+
+mallocForeignPtr :: Storable a => IO (ForeignPtr a)
+mallocForeignPtr = doMalloc undefined
+  where doMalloc :: Storable a => a -> IO (ForeignPtr a)
+        doMalloc a = IO $ \s ->
+         case newPinnedByteArray# size s of { (# s, mbarr# #) ->
+          (# s, MallocPtr mbarr# #)
+          }
+         where (I# size) = sizeOf a
+
+-- | similar to 'mallocForeignPtr', except that the size of the memory required
+-- is given explicitly as a number of bytes.
+mallocForeignPtrBytes :: Int -> IO (ForeignPtr a)
+mallocForeignPtrBytes (I# size) = IO $ \s ->
+  case newPinnedByteArray# size s      of { (# s, mbarr# #) ->
+   (# s, MallocPtr mbarr# #)
+  }
+
 addForeignPtrFinalizer :: ForeignPtr a -> IO () -> IO ()
 -- ^This function adds another finaliser to the given
 -- foreign object.  No guarantees are made on the order in
 -- which multiple finalisers for a single object are run.
 addForeignPtrFinalizer (ForeignPtr fo) finalizer = 
   IO $ \s -> case mkWeak# fo () finalizer s of { (# s1, w #) -> (# s1, () #) }
+addForeignPtrFinalizer (MallocPtr fo) finalizer = 
+  IO $ \s -> case mkWeak# fo () finalizer s of { (# s1, w #) -> (# s1, () #) }
 
 mkForeignPtr :: Ptr a -> IO (ForeignPtr a) {- not exported -}
 mkForeignPtr (Ptr obj) =  IO ( \ s# ->
@@ -118,6 +154,8 @@ touchForeignPtr :: ForeignPtr a -> IO ()
 -- until the interior pointer is no longer referenced.
 touchForeignPtr (ForeignPtr fo) 
    = IO $ \s -> case touch# fo s of s -> (# s, () #)
+touchForeignPtr (MallocPtr fo) 
+   = IO $ \s -> case touch# fo s of s -> (# s, () #)
 
 withForeignPtr :: ForeignPtr a -> (Ptr a -> IO b) -> IO b
 -- ^This is a way to look at the pointer living inside a
@@ -160,10 +198,12 @@ foreignPtrToPtr :: ForeignPtr a -> Ptr a
 -- 'touchForeignPtr'.  However, the later routines
 -- are occasionally preferred in tool generated marshalling code.
 foreignPtrToPtr (ForeignPtr fo) = Ptr (foreignObjToAddr# fo)
+foreignPtrToPtr (MallocPtr  fo) = Ptr (byteArrayContents# (unsafeCoerce# fo))
 
 castForeignPtr :: ForeignPtr a -> ForeignPtr b
 -- ^This function casts a 'ForeignPtr'
 -- parameterised by one type into another type.
 castForeignPtr (ForeignPtr a) = ForeignPtr a
+castForeignPtr (MallocPtr  a) = MallocPtr  a
 #endif