Ради простого примера, скажем, вы хотите добавить смещение к указателю.
Фасад:
module Main where
import Control.Monad (forM_)
import Data.Char (chr)
import Data.Word (Word8)
import Foreign.ForeignPtr (ForeignPtr, withForeignPtr)
import Foreign.Ptr (Ptr, plusPtr)
import Foreign.Storable (peek)
import System.IO.MMap (Mode(ReadOnly), mmapFileForeignPtr)
Да, вы написали, что вам не нужно значение Word8
, но я получил его с помощью peek
, чтобы продемонстрировать, что указатель действителен. У вас может возникнуть соблазн return
Ptr
изнутри withForeignPtr
, но документация предупреждает об этом:
Обратите внимание, что возвращать указатель из действия и использовать его после завершения действия небезопасно. Все виды использования указателя должны быть внутри скобки withForeignPtr
. Причина этой небезопасности та же, что и для unsafeForeignPtrToPtr
ниже: финализатор может работать раньше, чем ожидалось, поскольку компилятор может отслеживать только использование объекта ForeignPtr
, а не объекта Ptr
, созданного из него.
Код прост:
doStuff :: ForeignPtr Word8 -> Int -> IO ()
doStuff fp i =
withForeignPtr fp $ \p -> do
let addr = p `plusPtr` i
val <- peek addr :: IO Word8
print (addr, val, chr $ fromIntegral val)
Чтобы приблизить «Word8
в файле» из вашего вопроса, основная программа памяти отображает файл и использует этот буфер для работы с адресами памяти.
main :: IO ()
main = do
(p,offset,size) <- mmapFileForeignPtr path mode range
forM_ [0 .. size-1] $ \i -> do
doStuff p (offset + i)
where
path = "/tmp/input.dat"
mode = ReadOnly
range = Nothing
-- range = Just (4,3)
Выход:
(0x00007f1b40edd000,71,'G')
(0x00007f1b40edd001,117,'u')
(0x00007f1b40edd002,116,'t')
(0x00007f1b40edd003,101,'e')
(0x00007f1b40edd004,110,'n')
(0x00007f1b40edd005,32,' ')
(0x00007f1b40edd006,77,'M')
(0x00007f1b40edd007,111,'o')
(0x00007f1b40edd008,114,'r')
(0x00007f1b40edd009,103,'g')
(0x00007f1b40edd00a,101,'e')
(0x00007f1b40edd00b,110,'n')
(0x00007f1b40edd00c,33,'!')
(0x00007f1b40edd00d,10,'\n')