-- | A properly aligned ForeignPtr type. -- This can be currently achieved only by wasting some bytes. module Foreign.ForeignPtr.Aligned ( AlignedForeignPtr , Alignment, align, fromAlignment , mallocAlignedForeignPtr , mallocAlignedForeignPtrArray , mallocAlignedForeignPtrBytes , withAlignedForeignPtr , finalizeAlignedForeignPtr , touchAlignedForeignPtr , castAlignedForeignPtr ) where -------------------------------------------------------------------------------- import Data.Bits import Foreign.Ptr import Foreign.ForeignPtr import Foreign.Storable import System.IO.Unsafe -------------------------------------------------------------------------------- -- | Should be a power of two. newtype Alignment = Alignment { fromAlignment :: Int } deriving Show isPowerOfTwo :: Int -> Bool isPowerOfTwo k | k< 1 = False | k==1 = True | True = if odd k then False else isPowerOfTwo (k `div` 2) -- | A \"smart\" constructor which checks whether the input -- is a power of two. align :: Int -> Alignment align k = if isPowerOfTwo k then Alignment k else error "invalid alignment" -- | The aligned ForeignPtr type data AlignedForeignPtr a = AFPtr { _fptr :: {-# UNPACK #-} !(ForeignPtr a) , _offset :: {-# UNPACK #-} !Int } instance Show (AlignedForeignPtr a) where show afptr = unsafePerformIO $ withAlignedForeignPtr afptr $ \p -> return (show p) mallocAlignedForeignPtr :: Storable a => Alignment -> IO (AlignedForeignPtr a) mallocAlignedForeignPtr align = mallocAlignedForeignPtrArray align 1 mallocAlignedForeignPtrArray :: Storable a => Alignment -> Int -> IO (AlignedForeignPtr a) mallocAlignedForeignPtrArray align n = worker where worker = mallocAlignedForeignPtrBytes align (n * sizeOf undef) undef = ioAFPtrUndefined worker -- | This is here only to avoid the @ScopedTypeVariables@ language extension -- for more portability. ioAFPtrUndefined :: IO (AlignedForeignPtr a) -> a ioAFPtrUndefined _ = undefined mallocAlignedForeignPtrBytes :: Alignment -> Int -> IO (AlignedForeignPtr a) mallocAlignedForeignPtrBytes (Alignment align) n = do fptr <- mallocForeignPtrBytes (n+align) -- (n+align-1) would be enough, to be precise. But usually that's an odd number. ofs <- withForeignPtr fptr $ \p -> do let j = ptrToIntPtr p a = fromIntegral align :: IntPtr k = (j+a-1) .&. (complement (a-1)) return $ fromIntegral (k-j) return (AFPtr fptr ofs) withAlignedForeignPtr :: AlignedForeignPtr a -> (Ptr a -> IO b) -> IO b withAlignedForeignPtr (AFPtr fptr ofs) action = withForeignPtr fptr $ \p -> action (p `plusPtr` ofs) finalizeAlignedForeignPtr :: AlignedForeignPtr a -> IO () finalizeAlignedForeignPtr (AFPtr fptr ofs) = finalizeForeignPtr fptr touchAlignedForeignPtr :: AlignedForeignPtr a -> IO () touchAlignedForeignPtr (AFPtr fptr ofs) = touchForeignPtr fptr castAlignedForeignPtr :: AlignedForeignPtr a -> AlignedForeignPtr b castAlignedForeignPtr (AFPtr fptr ofs) = AFPtr (castForeignPtr fptr) ofs --------------------------------------------------------------------------------