{-# LANGUAGE Trustworthy, BangPatterns #-}
{-# LANGUAGE CPP, NoImplicitPrelude #-}
{-# OPTIONS_GHC -funbox-strict-fields #-}
module GHC.IO.Buffer (
Buffer(..), BufferState(..), CharBuffer, CharBufElem,
newByteBuffer,
newCharBuffer,
newBuffer,
emptyBuffer,
bufferRemove,
bufferAdd,
slideContents,
bufferAdjustL,
bufferAddOffset,
bufferAdjustOffset,
isEmptyBuffer,
isFullBuffer,
isFullCharBuffer,
isWriteBuffer,
bufferElems,
bufferAvailable,
bufferOffset,
summaryBuffer,
withBuffer,
withRawBuffer,
checkBuffer,
RawBuffer,
readWord8Buf,
writeWord8Buf,
RawCharBuffer,
peekCharBuf,
readCharBuf,
writeCharBuf,
readCharBufPtr,
writeCharBufPtr,
charSize,
) where
import GHC.Base
import GHC.Num
import GHC.Ptr
import GHC.Word
import GHC.Show
import GHC.Real
import GHC.List
import GHC.ForeignPtr (unsafeWithForeignPtr)
import Foreign.C.Types
import Foreign.ForeignPtr
import Foreign.Storable
#define CHARBUF_UTF32
type RawBuffer e = ForeignPtr e
readWord8Buf :: RawBuffer Word8 -> Int -> IO Word8
readWord8Buf :: RawBuffer Word8 -> Int -> IO Word8
readWord8Buf RawBuffer Word8
fp Int
ix = RawBuffer Word8 -> (Ptr Word8 -> IO Word8) -> IO Word8
forall a b. ForeignPtr a -> (Ptr a -> IO b) -> IO b
unsafeWithForeignPtr RawBuffer Word8
fp ((Ptr Word8 -> IO Word8) -> IO Word8)
-> (Ptr Word8 -> IO Word8) -> IO Word8
forall a b. (a -> b) -> a -> b
$ \Ptr Word8
p -> Ptr Word8 -> Int -> IO Word8
forall a b. Storable a => Ptr b -> Int -> IO a
peekByteOff Ptr Word8
p Int
ix
writeWord8Buf :: RawBuffer Word8 -> Int -> Word8 -> IO ()
writeWord8Buf :: RawBuffer Word8 -> Int -> Word8 -> IO ()
writeWord8Buf RawBuffer Word8
fp Int
ix Word8
w = RawBuffer Word8 -> (Ptr Word8 -> IO ()) -> IO ()
forall a b. ForeignPtr a -> (Ptr a -> IO b) -> IO b
unsafeWithForeignPtr RawBuffer Word8
fp ((Ptr Word8 -> IO ()) -> IO ()) -> (Ptr Word8 -> IO ()) -> IO ()
forall a b. (a -> b) -> a -> b
$ \Ptr Word8
p -> Ptr Word8 -> Int -> Word8 -> IO ()
forall a b. Storable a => Ptr b -> Int -> a -> IO ()
pokeByteOff Ptr Word8
p Int
ix Word8
w
#if defined(CHARBUF_UTF16)
type CharBufElem = Word16
#else
type CharBufElem = Char
#endif
type RawCharBuffer = RawBuffer CharBufElem
peekCharBuf :: RawCharBuffer -> Int -> IO Char
peekCharBuf :: RawCharBuffer -> Int -> IO Char
peekCharBuf RawCharBuffer
arr Int
ix = RawCharBuffer -> (Ptr Char -> IO Char) -> IO Char
forall a b. ForeignPtr a -> (Ptr a -> IO b) -> IO b
unsafeWithForeignPtr RawCharBuffer
arr ((Ptr Char -> IO Char) -> IO Char)
-> (Ptr Char -> IO Char) -> IO Char
forall a b. (a -> b) -> a -> b
$ \Ptr Char
p -> do
(Char
c,Int
_) <- Ptr Char -> Int -> IO (Char, Int)
readCharBufPtr Ptr Char
p Int
ix
Char -> IO Char
forall (m :: * -> *) a. Monad m => a -> m a
return Char
c
{-# INLINE readCharBuf #-}
readCharBuf :: RawCharBuffer -> Int -> IO (Char, Int)
readCharBuf :: RawCharBuffer -> Int -> IO (Char, Int)
readCharBuf RawCharBuffer
arr Int
ix = RawCharBuffer -> (Ptr Char -> IO (Char, Int)) -> IO (Char, Int)
forall a b. ForeignPtr a -> (Ptr a -> IO b) -> IO b
unsafeWithForeignPtr RawCharBuffer
arr ((Ptr Char -> IO (Char, Int)) -> IO (Char, Int))
-> (Ptr Char -> IO (Char, Int)) -> IO (Char, Int)
forall a b. (a -> b) -> a -> b
$ \Ptr Char
p -> Ptr Char -> Int -> IO (Char, Int)
readCharBufPtr Ptr Char
p Int
ix
{-# INLINE writeCharBuf #-}
writeCharBuf :: RawCharBuffer -> Int -> Char -> IO Int
writeCharBuf :: RawCharBuffer -> Int -> Char -> IO Int
writeCharBuf RawCharBuffer
arr Int
ix Char
c = RawCharBuffer -> (Ptr Char -> IO Int) -> IO Int
forall a b. ForeignPtr a -> (Ptr a -> IO b) -> IO b
unsafeWithForeignPtr RawCharBuffer
arr ((Ptr Char -> IO Int) -> IO Int) -> (Ptr Char -> IO Int) -> IO Int
forall a b. (a -> b) -> a -> b
$ \Ptr Char
p -> Ptr Char -> Int -> Char -> IO Int
writeCharBufPtr Ptr Char
p Int
ix Char
c
{-# INLINE readCharBufPtr #-}
readCharBufPtr :: Ptr CharBufElem -> Int -> IO (Char, Int)
#if defined(CHARBUF_UTF16)
readCharBufPtr p ix = do
c1 <- peekElemOff p ix
if (c1 < 0xd800 || c1 > 0xdbff)
then return (chr (fromIntegral c1), ix+1)
else do c2 <- peekElemOff p (ix+1)
return (unsafeChr ((fromIntegral c1 - 0xd800)*0x400 +
(fromIntegral c2 - 0xdc00) + 0x10000), ix+2)
#else
readCharBufPtr :: Ptr Char -> Int -> IO (Char, Int)
readCharBufPtr Ptr Char
p Int
ix = do Char
c <- Ptr Char -> Int -> IO Char
forall a. Storable a => Ptr a -> Int -> IO a
peekElemOff (Ptr Char -> Ptr Char
forall a b. Ptr a -> Ptr b
castPtr Ptr Char
p) Int
ix; (Char, Int) -> IO (Char, Int)
forall (m :: * -> *) a. Monad m => a -> m a
return (Char
c, Int
ixInt -> Int -> Int
forall a. Num a => a -> a -> a
+Int
1)
#endif
{-# INLINE writeCharBufPtr #-}
writeCharBufPtr :: Ptr CharBufElem -> Int -> Char -> IO Int
#if defined(CHARBUF_UTF16)
writeCharBufPtr p ix ch
| c < 0x10000 = do pokeElemOff p ix (fromIntegral c)
return (ix+1)
| otherwise = do let c' = c - 0x10000
pokeElemOff p ix (fromIntegral (c' `div` 0x400 + 0xd800))
pokeElemOff p (ix+1) (fromIntegral (c' `mod` 0x400 + 0xdc00))
return (ix+2)
where
c = ord ch
#else
writeCharBufPtr :: Ptr Char -> Int -> Char -> IO Int
writeCharBufPtr Ptr Char
p Int
ix Char
ch = do Ptr Char -> Int -> Char -> IO ()
forall a. Storable a => Ptr a -> Int -> a -> IO ()
pokeElemOff (Ptr Char -> Ptr Char
forall a b. Ptr a -> Ptr b
castPtr Ptr Char
p) Int
ix Char
ch; Int -> IO Int
forall (m :: * -> *) a. Monad m => a -> m a
return (Int
ixInt -> Int -> Int
forall a. Num a => a -> a -> a
+Int
1)
#endif
charSize :: Int
#if defined(CHARBUF_UTF16)
charSize = 2
#else
charSize :: Int
charSize = Int
4
#endif
data Buffer e
= Buffer {
forall e. Buffer e -> RawBuffer e
bufRaw :: !(RawBuffer e),
forall e. Buffer e -> BufferState
bufState :: BufferState,
forall e. Buffer e -> Int
bufSize :: !Int,
forall e. Buffer e -> Word64
bufOffset :: !Word64,
forall e. Buffer e -> Int
bufL :: !Int,
forall e. Buffer e -> Int
bufR :: !Int
}
#if defined(CHARBUF_UTF16)
type CharBuffer = Buffer Word16
#else
type CharBuffer = Buffer Char
#endif
data BufferState = ReadBuffer | WriteBuffer
deriving BufferState -> BufferState -> Bool
(BufferState -> BufferState -> Bool)
-> (BufferState -> BufferState -> Bool) -> Eq BufferState
forall a. (a -> a -> Bool) -> (a -> a -> Bool) -> Eq a
/= :: BufferState -> BufferState -> Bool
$c/= :: BufferState -> BufferState -> Bool
== :: BufferState -> BufferState -> Bool
$c== :: BufferState -> BufferState -> Bool
Eq
withBuffer :: Buffer e -> (Ptr e -> IO a) -> IO a
withBuffer :: forall e a. Buffer e -> (Ptr e -> IO a) -> IO a
withBuffer Buffer{ bufRaw :: forall e. Buffer e -> RawBuffer e
bufRaw=RawBuffer e
raw } Ptr e -> IO a
f = RawBuffer e -> (Ptr e -> IO a) -> IO a
forall a b. ForeignPtr a -> (Ptr a -> IO b) -> IO b
withForeignPtr (RawBuffer e -> RawBuffer e
forall a b. ForeignPtr a -> ForeignPtr b
castForeignPtr RawBuffer e
raw) Ptr e -> IO a
f
withRawBuffer :: RawBuffer e -> (Ptr e -> IO a) -> IO a
withRawBuffer :: forall a b. ForeignPtr a -> (Ptr a -> IO b) -> IO b
withRawBuffer RawBuffer e
raw Ptr e -> IO a
f = RawBuffer e -> (Ptr e -> IO a) -> IO a
forall a b. ForeignPtr a -> (Ptr a -> IO b) -> IO b
withForeignPtr (RawBuffer e -> RawBuffer e
forall a b. ForeignPtr a -> ForeignPtr b
castForeignPtr RawBuffer e
raw) Ptr e -> IO a
f
isEmptyBuffer :: Buffer e -> Bool
isEmptyBuffer :: forall e. Buffer e -> Bool
isEmptyBuffer Buffer{ bufL :: forall e. Buffer e -> Int
bufL=Int
l, bufR :: forall e. Buffer e -> Int
bufR=Int
r } = Int
l Int -> Int -> Bool
forall a. Eq a => a -> a -> Bool
== Int
r
isFullBuffer :: Buffer e -> Bool
isFullBuffer :: forall e. Buffer e -> Bool
isFullBuffer Buffer{ bufR :: forall e. Buffer e -> Int
bufR=Int
w, bufSize :: forall e. Buffer e -> Int
bufSize=Int
s } = Int
s Int -> Int -> Bool
forall a. Eq a => a -> a -> Bool
== Int
w
isFullCharBuffer :: Buffer e -> Bool
#if defined(CHARBUF_UTF16)
isFullCharBuffer buf = bufferAvailable buf < 2
#else
isFullCharBuffer :: forall e. Buffer e -> Bool
isFullCharBuffer = Buffer e -> Bool
forall e. Buffer e -> Bool
isFullBuffer
#endif
isWriteBuffer :: Buffer e -> Bool
isWriteBuffer :: forall e. Buffer e -> Bool
isWriteBuffer Buffer e
buf = case Buffer e -> BufferState
forall e. Buffer e -> BufferState
bufState Buffer e
buf of
BufferState
WriteBuffer -> Bool
True
BufferState
ReadBuffer -> Bool
False
bufferElems :: Buffer e -> Int
bufferElems :: forall e. Buffer e -> Int
bufferElems Buffer{ bufR :: forall e. Buffer e -> Int
bufR=Int
w, bufL :: forall e. Buffer e -> Int
bufL=Int
r } = Int
w Int -> Int -> Int
forall a. Num a => a -> a -> a
- Int
r
bufferAvailable :: Buffer e -> Int
bufferAvailable :: forall e. Buffer e -> Int
bufferAvailable Buffer{ bufR :: forall e. Buffer e -> Int
bufR=Int
w, bufSize :: forall e. Buffer e -> Int
bufSize=Int
s } = Int
s Int -> Int -> Int
forall a. Num a => a -> a -> a
- Int
w
bufferRemove :: Int -> Buffer e -> Buffer e
bufferRemove :: forall e. Int -> Buffer e -> Buffer e
bufferRemove Int
i buf :: Buffer e
buf@Buffer{ bufL :: forall e. Buffer e -> Int
bufL=Int
r } = Int -> Buffer e -> Buffer e
forall e. Int -> Buffer e -> Buffer e
bufferAdjustL (Int
rInt -> Int -> Int
forall a. Num a => a -> a -> a
+Int
i) Buffer e
buf
bufferAdjustL :: Int -> Buffer e -> Buffer e
bufferAdjustL :: forall e. Int -> Buffer e -> Buffer e
bufferAdjustL Int
l buf :: Buffer e
buf@Buffer{ bufR :: forall e. Buffer e -> Int
bufR=Int
w }
| Int
l Int -> Int -> Bool
forall a. Eq a => a -> a -> Bool
== Int
w = Buffer e
buf{ bufL :: Int
bufL=Int
0, bufR :: Int
bufR=Int
0 }
| Bool
otherwise = Buffer e
buf{ bufL :: Int
bufL=Int
l, bufR :: Int
bufR=Int
w }
bufferAdd :: Int -> Buffer e -> Buffer e
bufferAdd :: forall e. Int -> Buffer e -> Buffer e
bufferAdd Int
i buf :: Buffer e
buf@Buffer{ bufR :: forall e. Buffer e -> Int
bufR=Int
w } = Buffer e
buf{ bufR :: Int
bufR=Int
wInt -> Int -> Int
forall a. Num a => a -> a -> a
+Int
i }
bufferOffset :: Buffer e -> Word64
bufferOffset :: forall e. Buffer e -> Word64
bufferOffset Buffer{ bufOffset :: forall e. Buffer e -> Word64
bufOffset=Word64
off } = Word64
off
bufferAdjustOffset :: Word64 -> Buffer e -> Buffer e
bufferAdjustOffset :: forall e. Word64 -> Buffer e -> Buffer e
bufferAdjustOffset Word64
offs Buffer e
buf = Buffer e
buf{ bufOffset :: Word64
bufOffset=Word64
offs }
bufferAddOffset :: Int -> Buffer e -> Buffer e
bufferAddOffset :: forall e. Int -> Buffer e -> Buffer e
bufferAddOffset Int
offs buf :: Buffer e
buf@Buffer{ bufOffset :: forall e. Buffer e -> Word64
bufOffset=Word64
w } =
Buffer e
buf{ bufOffset :: Word64
bufOffset=Word64
wWord64 -> Word64 -> Word64
forall a. Num a => a -> a -> a
+(Int -> Word64
forall a b. (Integral a, Num b) => a -> b
fromIntegral Int
offs) }
emptyBuffer :: RawBuffer e -> Int -> BufferState -> Buffer e
emptyBuffer :: forall e. RawBuffer e -> Int -> BufferState -> Buffer e
emptyBuffer RawBuffer e
raw Int
sz BufferState
state =
Buffer :: forall e.
RawBuffer e
-> BufferState -> Int -> Word64 -> Int -> Int -> Buffer e
Buffer{ bufRaw :: RawBuffer e
bufRaw=RawBuffer e
raw, bufState :: BufferState
bufState=BufferState
state, bufOffset :: Word64
bufOffset=Word64
0, bufR :: Int
bufR=Int
0, bufL :: Int
bufL=Int
0, bufSize :: Int
bufSize=Int
sz }
newByteBuffer :: Int -> BufferState -> IO (Buffer Word8)
newByteBuffer :: Int -> BufferState -> IO (Buffer Word8)
newByteBuffer Int
c BufferState
st = Int -> Int -> BufferState -> IO (Buffer Word8)
forall e. Int -> Int -> BufferState -> IO (Buffer e)
newBuffer Int
c Int
c BufferState
st
newCharBuffer :: Int -> BufferState -> IO CharBuffer
newCharBuffer :: Int -> BufferState -> IO CharBuffer
newCharBuffer Int
c BufferState
st = Int -> Int -> BufferState -> IO CharBuffer
forall e. Int -> Int -> BufferState -> IO (Buffer e)
newBuffer (Int
c Int -> Int -> Int
forall a. Num a => a -> a -> a
* Int
charSize) Int
c BufferState
st
newBuffer :: Int -> Int -> BufferState -> IO (Buffer e)
newBuffer :: forall e. Int -> Int -> BufferState -> IO (Buffer e)
newBuffer Int
bytes Int
sz BufferState
state = do
ForeignPtr e
fp <- Int -> IO (ForeignPtr e)
forall a. Int -> IO (ForeignPtr a)
mallocForeignPtrBytes Int
bytes
Buffer e -> IO (Buffer e)
forall (m :: * -> *) a. Monad m => a -> m a
return (ForeignPtr e -> Int -> BufferState -> Buffer e
forall e. RawBuffer e -> Int -> BufferState -> Buffer e
emptyBuffer ForeignPtr e
fp Int
sz BufferState
state)
slideContents :: Buffer Word8 -> IO (Buffer Word8)
slideContents :: Buffer Word8 -> IO (Buffer Word8)
slideContents buf :: Buffer Word8
buf@Buffer{ bufL :: forall e. Buffer e -> Int
bufL=Int
l, bufR :: forall e. Buffer e -> Int
bufR=Int
r, bufRaw :: forall e. Buffer e -> RawBuffer e
bufRaw=RawBuffer Word8
raw } = do
let elems :: Int
elems = Int
r Int -> Int -> Int
forall a. Num a => a -> a -> a
- Int
l
RawBuffer Word8 -> (Ptr Word8 -> IO ()) -> IO ()
forall a b. ForeignPtr a -> (Ptr a -> IO b) -> IO b
withRawBuffer RawBuffer Word8
raw ((Ptr Word8 -> IO ()) -> IO ()) -> (Ptr Word8 -> IO ()) -> IO ()
forall a b. (a -> b) -> a -> b
$ \Ptr Word8
p ->
do Ptr Word8
_ <- Ptr Word8 -> Ptr Word8 -> CSize -> IO (Ptr Word8)
forall a. Ptr a -> Ptr a -> CSize -> IO (Ptr a)
memmove Ptr Word8
p (Ptr Word8
p Ptr Word8 -> Int -> Ptr Word8
forall a b. Ptr a -> Int -> Ptr b
`plusPtr` Int
l) (Int -> CSize
forall a b. (Integral a, Num b) => a -> b
fromIntegral Int
elems)
() -> IO ()
forall (m :: * -> *) a. Monad m => a -> m a
return ()
Buffer Word8 -> IO (Buffer Word8)
forall (m :: * -> *) a. Monad m => a -> m a
return Buffer Word8
buf{ bufL :: Int
bufL=Int
0, bufR :: Int
bufR=Int
elems }
foreign import ccall unsafe "memmove"
memmove :: Ptr a -> Ptr a -> CSize -> IO (Ptr a)
summaryBuffer :: Buffer a -> String
summaryBuffer :: forall a. Buffer a -> String
summaryBuffer !Buffer a
buf
= String -> String
ppr (RawBuffer a -> String
forall a. Show a => a -> String
show (RawBuffer a -> String) -> RawBuffer a -> String
forall a b. (a -> b) -> a -> b
$ Buffer a -> RawBuffer a
forall e. Buffer e -> RawBuffer e
bufRaw Buffer a
buf) String -> String -> String
forall a. [a] -> [a] -> [a]
++ String
"@buf" String -> String -> String
forall a. [a] -> [a] -> [a]
++ Int -> String
forall a. Show a => a -> String
show (Buffer a -> Int
forall e. Buffer e -> Int
bufSize Buffer a
buf)
String -> String -> String
forall a. [a] -> [a] -> [a]
++ String
"(" String -> String -> String
forall a. [a] -> [a] -> [a]
++ Int -> String
forall a. Show a => a -> String
show (Buffer a -> Int
forall e. Buffer e -> Int
bufL Buffer a
buf) String -> String -> String
forall a. [a] -> [a] -> [a]
++ String
"-" String -> String -> String
forall a. [a] -> [a] -> [a]
++ Int -> String
forall a. Show a => a -> String
show (Buffer a -> Int
forall e. Buffer e -> Int
bufR Buffer a
buf) String -> String -> String
forall a. [a] -> [a] -> [a]
++ String
")"
String -> String -> String
forall a. [a] -> [a] -> [a]
++ String
" (>=" String -> String -> String
forall a. [a] -> [a] -> [a]
++ Word64 -> String
forall a. Show a => a -> String
show (Buffer a -> Word64
forall e. Buffer e -> Word64
bufOffset Buffer a
buf) String -> String -> String
forall a. [a] -> [a] -> [a]
++ String
")"
where ppr :: String -> String
ppr :: String -> String
ppr (Char
'0':Char
'x':String
xs) = let p :: String
p = (Char -> Bool) -> String -> String
forall a. (a -> Bool) -> [a] -> [a]
dropWhile (Char -> Char -> Bool
forall a. Eq a => a -> a -> Bool
==Char
'0') String
xs
in if String -> Bool
forall a. [a] -> Bool
null String
p then String
"0x0" else Char
'0'Char -> String -> String
forall a. a -> [a] -> [a]
:Char
'x'Char -> String -> String
forall a. a -> [a] -> [a]
:String
p
ppr String
x = String
x
checkBuffer :: Buffer a -> IO ()
checkBuffer :: forall a. Buffer a -> IO ()
checkBuffer buf :: Buffer a
buf@Buffer{ bufState :: forall e. Buffer e -> BufferState
bufState = BufferState
state, bufL :: forall e. Buffer e -> Int
bufL=Int
r, bufR :: forall e. Buffer e -> Int
bufR=Int
w, bufSize :: forall e. Buffer e -> Int
bufSize=Int
size } = do
Buffer a -> Bool -> IO ()
forall a. Buffer a -> Bool -> IO ()
check Buffer a
buf (
Int
size Int -> Int -> Bool
forall a. Ord a => a -> a -> Bool
> Int
0
Bool -> Bool -> Bool
&& Int
r Int -> Int -> Bool
forall a. Ord a => a -> a -> Bool
<= Int
w
Bool -> Bool -> Bool
&& Int
w Int -> Int -> Bool
forall a. Ord a => a -> a -> Bool
<= Int
size
Bool -> Bool -> Bool
&& ( Int
r Int -> Int -> Bool
forall a. Eq a => a -> a -> Bool
/= Int
w Bool -> Bool -> Bool
|| BufferState
state BufferState -> BufferState -> Bool
forall a. Eq a => a -> a -> Bool
== BufferState
WriteBuffer Bool -> Bool -> Bool
|| (Int
r Int -> Int -> Bool
forall a. Eq a => a -> a -> Bool
== Int
0 Bool -> Bool -> Bool
&& Int
w Int -> Int -> Bool
forall a. Eq a => a -> a -> Bool
== Int
0) )
Bool -> Bool -> Bool
&& ( BufferState
state BufferState -> BufferState -> Bool
forall a. Eq a => a -> a -> Bool
/= BufferState
WriteBuffer Bool -> Bool -> Bool
|| Int
w Int -> Int -> Bool
forall a. Ord a => a -> a -> Bool
< Int
size )
)
check :: Buffer a -> Bool -> IO ()
check :: forall a. Buffer a -> Bool -> IO ()
check Buffer a
_ Bool
True = () -> IO ()
forall (m :: * -> *) a. Monad m => a -> m a
return ()
check Buffer a
buf Bool
False = String -> IO ()
forall a. String -> a
errorWithoutStackTrace (String
"buffer invariant violation: " String -> String -> String
forall a. [a] -> [a] -> [a]
++ Buffer a -> String
forall a. Buffer a -> String
summaryBuffer Buffer a
buf)