Movatterモバイル変換
[0]ホーム
{-# LANGUAGE Trustworthy, BangPatterns #-}{-# LANGUAGE CPP, NoImplicitPrelude #-}{-# OPTIONS_GHC -funbox-strict-fields #-}------------------------------------------------------------------------------- |-- Module : GHC.IO.Buffer-- Copyright : (c) The University of Glasgow 2008-- License : see libraries/base/LICENSE---- Maintainer : cvs-ghc@haskell.org-- Stability : internal-- Portability : non-portable (GHC Extensions)---- Buffers used in the IO system-------------------------------------------------------------------------------moduleGHC.IO.Buffer(-- * Buffers of any elementBuffer(..),BufferState(..),CharBuffer,CharBufElem,-- ** CreationnewByteBuffer,newCharBuffer,newBuffer,emptyBuffer,-- ** Insertion/removalbufferRemove,bufferAdd,slideContents,bufferAdjustL,-- ** InspectingisEmptyBuffer,isFullBuffer,isFullCharBuffer,isWriteBuffer,bufferElems,bufferAvailable,summaryBuffer,-- ** Operating on the raw buffer as a PtrwithBuffer,withRawBuffer,-- ** AssertionscheckBuffer,-- * Raw buffersRawBuffer,readWord8Buf,writeWord8Buf,RawCharBuffer,peekCharBuf,readCharBuf,writeCharBuf,readCharBufPtr,writeCharBufPtr,charSize,)whereimportGHC.Base-- import GHC.IOimportGHC.NumimportGHC.PtrimportGHC.WordimportGHC.ShowimportGHC.RealimportForeign.C.TypesimportForeign.ForeignPtrimportForeign.Storable-- Char buffers use either UTF-16 or UTF-32, with the endianness matching-- the endianness of the host.---- Invariants:-- * a Char buffer consists of *valid* UTF-16 or UTF-32-- * only whole characters: no partial surrogate pairs#define CHARBUF_UTF32-- #define CHARBUF_UTF16---- NB. it won't work to just change this to CHARBUF_UTF16. Some of-- the code to make this work is there, and it has been tested with-- the Iconv codec, but there are some pieces that are known to be-- broken. In particular, the built-in codecs-- e.g. GHC.IO.Encoding.UTF{8,16,32} need to use isFullCharBuffer or-- similar in place of the ow >= os comparisons.-- ----------------------------------------------------------------------------- Raw blocks of datatypeRawBuffere=ForeignPtrereadWord8Buf::RawBufferWord8->Int->IOWord8readWord8Bufarrix=withForeignPtrarr$\p->peekByteOffpixwriteWord8Buf::RawBufferWord8->Int->Word8->IO()writeWord8Bufarrixw=withForeignPtrarr$\p->pokeByteOffpixw#if defined(CHARBUF_UTF16)typeCharBufElem=Word16#elsetypeCharBufElem=Char#endiftypeRawCharBuffer=RawBufferCharBufElempeekCharBuf::RawCharBuffer->Int->IOCharpeekCharBufarrix=withForeignPtrarr$\p->do(c,_)<-readCharBufPtrpixreturnc{-# INLINEreadCharBuf#-}readCharBuf::RawCharBuffer->Int->IO(Char,Int)readCharBufarrix=withForeignPtrarr$\p->readCharBufPtrpix{-# INLINEwriteCharBuf#-}writeCharBuf::RawCharBuffer->Int->Char->IOIntwriteCharBufarrixc=withForeignPtrarr$\p->writeCharBufPtrpixc{-# INLINEreadCharBufPtr#-}readCharBufPtr::PtrCharBufElem->Int->IO(Char,Int)#if defined(CHARBUF_UTF16)readCharBufPtrpix=doc1<-peekElemOffpixif(c1<0xd800||c1>0xdbff)thenreturn(chr(fromIntegralc1),ix+1)elsedoc2<-peekElemOffp(ix+1)return(unsafeChr((fromIntegralc1-0xd800)*0x400+(fromIntegralc2-0xdc00)+0x10000),ix+2)#elsereadCharBufPtrpix=doc<-peekElemOff(castPtrp)ix;return(c,ix+1)#endif{-# INLINEwriteCharBufPtr#-}writeCharBufPtr::PtrCharBufElem->Int->Char->IOInt#if defined(CHARBUF_UTF16)writeCharBufPtrpixch|c<0x10000=dopokeElemOffpix(fromIntegralc)return(ix+1)|otherwise=doletc'=c-0x10000pokeElemOffpix(fromIntegral(c'`div`0x400+0xd800))pokeElemOffp(ix+1)(fromIntegral(c'`mod`0x400+0xdc00))return(ix+2)wherec=ordch#elsewriteCharBufPtrpixch=dopokeElemOff(castPtrp)ixch;return(ix+1)#endifcharSize::Int#if defined(CHARBUF_UTF16)charSize=2#elsecharSize=4#endif-- ----------------------------------------------------------------------------- Buffers-- | A mutable array of bytes that can be passed to foreign functions.---- The buffer is represented by a record, where the record contains-- the raw buffer and the start/end points of the filled portion. The-- buffer contents itself is mutable, but the rest of the record is-- immutable. This is a slightly odd mix, but it turns out to be-- quite practical: by making all the buffer metadata immutable, we-- can have operations on buffer metadata outside of the IO monad.---- The "live" elements of the buffer are those between the 'bufL' and-- 'bufR' offsets. In an empty buffer, 'bufL' is equal to 'bufR', but-- they might not be zero: for example, the buffer might correspond to-- a memory-mapped file and in which case 'bufL' will point to the-- next location to be written, which is not necessarily the beginning-- of the file.dataBuffere=Buffer{bufRaw::!(RawBuffere),bufState::BufferState,bufSize::!Int,-- in elements, not bytesbufL::!Int,-- offset of first item in the bufferbufR::!Int-- offset of last item + 1}#if defined(CHARBUF_UTF16)typeCharBuffer=BufferWord16#elsetypeCharBuffer=BufferChar#endifdataBufferState=ReadBuffer|WriteBufferderivingEq-- ^ @since 4.2.0.0withBuffer::Buffere->(Ptre->IOa)->IOawithBufferBuffer{bufRaw=raw}f=withForeignPtr(castForeignPtrraw)fwithRawBuffer::RawBuffere->(Ptre->IOa)->IOawithRawBufferrawf=withForeignPtr(castForeignPtrraw)fisEmptyBuffer::Buffere->BoolisEmptyBufferBuffer{bufL=l,bufR=r}=l==risFullBuffer::Buffere->BoolisFullBufferBuffer{bufR=w,bufSize=s}=s==w-- if a Char buffer does not have room for a surrogate pair, it is "full"isFullCharBuffer::Buffere->Bool#if defined(CHARBUF_UTF16)isFullCharBufferbuf=bufferAvailablebuf<2#elseisFullCharBuffer=isFullBuffer#endifisWriteBuffer::Buffere->BoolisWriteBufferbuf=casebufStatebufofWriteBuffer->TrueReadBuffer->FalsebufferElems::Buffere->IntbufferElemsBuffer{bufR=w,bufL=r}=w-rbufferAvailable::Buffere->IntbufferAvailableBuffer{bufR=w,bufSize=s}=s-wbufferRemove::Int->Buffere->BufferebufferRemoveibuf@Buffer{bufL=r}=bufferAdjustL(r+i)bufbufferAdjustL::Int->Buffere->BufferebufferAdjustLlbuf@Buffer{bufR=w}|l==w=buf{bufL=0,bufR=0}|otherwise=buf{bufL=l,bufR=w}bufferAdd::Int->Buffere->BufferebufferAddibuf@Buffer{bufR=w}=buf{bufR=w+i}emptyBuffer::RawBuffere->Int->BufferState->BuffereemptyBufferrawszstate=Buffer{bufRaw=raw,bufState=state,bufR=0,bufL=0,bufSize=sz}newByteBuffer::Int->BufferState->IO(BufferWord8)newByteBuffercst=newBufferccstnewCharBuffer::Int->BufferState->IOCharBuffernewCharBuffercst=newBuffer(c*charSize)cstnewBuffer::Int->Int->BufferState->IO(Buffere)newBufferbytesszstate=dofp<-mallocForeignPtrBytesbytesreturn(emptyBufferfpszstate)-- | slides the contents of the buffer to the beginningslideContents::BufferWord8->IO(BufferWord8)slideContentsbuf@Buffer{bufL=l,bufR=r,bufRaw=raw}=doletelems=r-lwithRawBufferraw$\p->do_<-memmovep(p`plusPtr`l)(fromIntegralelems)return()returnbuf{bufL=0,bufR=elems}foreignimportccallunsafe"memmove"memmove::Ptra->Ptra->CSize->IO(Ptra)summaryBuffer::Buffera->StringsummaryBuffer!buf-- Strict => slightly better code="buf"++show(bufSizebuf)++"("++show(bufLbuf)++"-"++show(bufRbuf)++")"-- INVARIANTS on Buffers:-- * r <= w-- * if r == w, and the buffer is for reading, then r == 0 && w == 0-- * a write buffer is never full. If an operation-- fills up the buffer, it will always flush it before-- returning.-- * a read buffer may be full as a result of hLookAhead. In normal-- operation, a read buffer always has at least one character of space.checkBuffer::Buffera->IO()checkBufferbuf@Buffer{bufState=state,bufL=r,bufR=w,bufSize=size}=docheckbuf(size>0&&r<=w&&w<=size&&(r/=w||state==WriteBuffer||(r==0&&w==0))&&(state/=WriteBuffer||w<size)-- write buffer is never full)check::Buffera->Bool->IO()check_True=return()checkbufFalse=errorWithoutStackTrace("buffer invariant violation: "++summaryBufferbuf)
[8]ページ先頭