{- | In principle you can traverse through a storable vector using repeated calls to @viewL@ or using @index@. However this needs a bit of pointer arrangement and allocation. This data structure should make loops optimally fast. -} module Data.StorableVector.Pointer ( Pointer(..), cons, viewL, switchL, ) where -- import qualified Data.StorableVector as V import qualified Data.StorableVector.Base as VB import qualified Foreign.ForeignPtr as FPtr import Foreign.Marshal.Array (advancePtr, ) import Foreign.Storable (Storable, peek, ) import Foreign (Ptr, ) import qualified System.Unsafe as Unsafe {- The reference to the ForeignPtr asserts, that the array is maintained and thus is not garbage collected. The Ptr we use for traversing would not achieve this. -} {- | We might have name the data type iterator. -} data Pointer a = Pointer { fptr :: {-# UNPACK #-} !(FPtr.ForeignPtr a), ptr :: {-# UNPACK #-} !(Ptr a), left :: {-# UNPACK #-} !Int } {-# INLINE cons #-} cons :: Storable a => VB.Vector a -> Pointer a cons (VB.SV fp s l) = Pointer fp (advancePtr (Unsafe.foreignPtrToPtr fp) s) l {-# INLINE viewL #-} viewL :: Storable a => Pointer a -> Maybe (a, Pointer a) viewL = switchL Nothing (curry Just) {-# INLINE switchL #-} switchL :: Storable a => b -> (a -> Pointer a -> b) -> Pointer a -> b switchL n j (Pointer fp p l) = if l<=0 then n else j (VB.inlinePerformIO (peek p)) (Pointer fp (advancePtr p 1) (l-1)) -- Unsafe.performIO at this place would make SpeedPointer test 0.5 s slower