Data-Rope 0.1 → 0.2
raw patch · 4 files changed
+113/−9 lines, 4 filesPVP ok
version bump matches the API change (PVP)
API changes (from Hackage documentation)
+ Data.Rope: elemIndex' :: Word8 -> Rope -> Maybe Int
+ Data.Rope: hGetContents :: Handle -> IO Rope
+ Data.Rope: hGetLine :: Handle -> IO Rope
+ Data.Rope.Internals: c2w :: Char -> Word8
+ Data.Rope.Internals: w2c :: Word8 -> Char
Files
- Data-Rope.cabal +1/−1
- Data/Rope.lhs +93/−7
- Data/Rope/Char8.lhs +11/−0
- Data/Rope/Internals.hsc +8/−1
Data-Rope.cabal view
@@ -1,5 +1,5 @@ Name: Data-Rope-Version: 0.1+Version: 0.2 Synopsis: Ropes, an alternative to (Byte)Strings. Description: Ropes : an alternative to Strings, a time and space-efficient representation of character
Data/Rope.lhs view
@@ -46,10 +46,13 @@ -- * Indexing 'Rope's index, elemIndex,+ elemIndex', elemIndices, -- * Input and Output readFile, hGet,+ hGetLine,+ hGetContents, hPut, hPutStrLn, hPutStr,@@ -72,7 +75,7 @@ import qualified Data.ByteString.Internal as B import Data.String import Data.Word-+import Control.Exception (finally) #if __GLASGOW_HASKELL__ >=608 import GHC.IO (IO(IO),unsafePerformIO,unsafeInterleaveIO) import GHC.Base (realWorld#)@@ -83,11 +86,13 @@ import System.IO.Unsafe #endif import Data.Maybe-import GHC.Conc+import GHC.Conc (par) import System.Posix (openFd,closeFd,defaultFileFlags,getFileStatus, fileSize,OpenMode(..))-import System.IO hiding (hPutStrLn,hPutStr,putStrLn,putStr,readFile)+import System.IO (hGetBuf,hPutBuf,hSeek,hTell,hFileSize,+ hPutChar, stdout, hClose)+ import qualified Prelude(length,map,splitAt) import Prelude hiding (length,null,head,tail,last,init,map,reverse, foldl,foldr,@@ -298,7 +303,7 @@ -} -- | O(1) Tests whether a 'Rope' is empty. null::Rope->Bool-null x=length x>0+null x=length x==0 -- | O(1) Length of a 'Rope'. length::Rope->Int@@ -626,12 +631,13 @@ index_ (Concat{r,l}) i_ |i_>=length l = index_ r (i_-length l) |otherwise = index_ l i_+ {- index_ (File{handle,position}) i_= unsafePerformIO $ alloca $ \cc->do hSeek handle AbsoluteSeek $ fromIntegral $ position+i_ hGetBuf handle cc 1 peek cc-+-} -- | O(n) returns the index of the first element equal to the query element. This implementation -- uses memchr at leaves, and explores the rope in parallel (with 'GHC.Conc.par').@@ -664,6 +670,36 @@ x<-peek ptr if x==w then return $ Just i else loop (ptr`plusPtr`1) (i+1) l +-- | O(n) Same as 'elemIndex', but explores the 'Rope' sequentially. Useful for+-- 'Rope's loaded lazily with 'readFile'.++elemIndex'::Word8->Rope->Maybe Int+elemIndex' w rope=+ elemIndex_ 0 rope+ where+ elemIndex_ i (String{contents,offset,length_})=+ inlinePerformIO $ withForeignPtr contents $ \con->do+ ptr<-memchr (con`plusPtr`offset) w (fromIntegral length_)+ return $ if ptr==nullPtr then Nothing else Just $ i+offset+(ptr`minusPtr`con)+ + elemIndex_ i (Concat{l,r})=+ case elemIndex_ i l of+ Nothing->elemIndex_ (i+length l) r+ a->a+ + elemIndex_ i (File{handle,position,length_})=+ unsafePerformIO $ allocaBytes length_ $ \c->do+ hSeek handle AbsoluteSeek $ fromIntegral position+ l<-hGetBuf handle c length_+ x<-loop c 0 l+ return $ x>>=(return.(+i))+ + loop ptr i l+ | i>=l = return Nothing+ | otherwise = do+ x<-peek ptr+ if x==w then return $ Just i else loop (ptr`plusPtr`1) (i+1) l+ -- | O(n) returns the list of all positions where the queried elements occurs in the 'Rope'. -- This implementation uses memchr. @@ -921,8 +957,7 @@ putStrLn::Rope->IO() putStrLn=hPutStrLn stdout --+-- | fromPtr encapsule un pointeur, un offset et une longueur dans un @Rope@.. fromPtr::ForeignPtr Word8->Int->Int->IO Rope fromPtr fp offset s | s<=leafSize = withForeignPtr fp $ \p->do@@ -983,6 +1018,7 @@ fromPtr fp 0 (fromIntegral s) + -- | Strict hGet. The whole rope is constructed. hGet::Handle->Int->IO Rope hGet handle length_=do@@ -1012,5 +1048,55 @@ bb<-buildRope handle (position+fromIntegral a) b return $ Concat { length_=len,l=aa,r=bb,sizeC=size aa+size bb } +-- | Returns the next line in the input 'Handle'. If you need to iterate 'hGetLine',+-- it may be more efficient to first @mmap@ the file using 'readFile', or even load+-- it with then iterate+-- @'breakByte' 0x0a@ : 'hGetLine' allocates a buffer to read the file+-- and may waste most of this space if the lines are shorter than the standard buffer+-- size of this module.+hGetLine::Handle->IO Rope+hGetLine h=+ hGetLine' empty+ + where+ hGetLine' x=do+ contents<-mallocForeignPtrBytes leafSize+ withForeignPtr contents $ \con->do+ l<-hGetBuf h con leafSize+ let readBytes=min l leafSize+ if readBytes<=0 then return x else do+ ptr<-memchr con 0x0a (fromIntegral readBytes)+ if ptr==nullPtr then do+ i0<-mallocForeignPtr+ withForeignPtr i0 $ \i->poke i readBytes+ let y=String { contents,i0,offset=0,length_=readBytes }+ hGetLine' (x`append`y)+ + else do+ + i0<-mallocForeignPtr+ let lineLen=ptr`minusPtr`con+ y=String { contents,i0,offset=0,length_=lineLen }+ withForeignPtr i0 $ \i->poke i lineLen+ hSeek h RelativeSeek (fromIntegral $ lineLen-readBytes+1)+ return $ x`append`y+ +-- | Reads the contents of a file handle strictly, then closes it.++hGetContents::Handle->IO Rope+hGetContents h=finally (hGetContents' empty) (hClose h)++ where+ hGetContents' r=do+ contents<-mallocForeignPtrBytes leafSize+ withForeignPtr contents $ \l->do+ x<-hGetBuf h l leafSize+ i0<-mallocForeignPtr+ withForeignPtr i0 $ \i->poke i x+ let y=String { contents,i0,offset=0,length_=x }++ if x==0 then return r else+ if x<leafSize then return $ r`append`y else+ hGetContents' $ r`append`y \end{code}
+ Data/Rope/Char8.lhs view
@@ -0,0 +1,11 @@+\begin{code}+module Data.Rope.Char8 where++import qualified Data.Rope as R+import Data.Rope.Internals++singleton::Word8->Rope+singleton x=(R.singleton).w2c+++\end{code}
Data/Rope/Internals.hsc view
@@ -7,7 +7,7 @@ import Foreign.Storable import Foreign.C.Types import Data.Word-+import GHC.Base foreign import ccall unsafe "sys/mman.h mmap" c_mmap:: Ptr a->CSize->CInt->CInt->CInt->CInt->IO (Ptr Word8)@@ -32,3 +32,10 @@ c_MAP_FILE::CInt c_MAP_FILE= #const MAP_FILE+++w2c::Word8->Char+w2c=unsafeChr.fromIntegral++c2w::Char->Word8+c2w=fromIntegral.ord