Commits

Bryan O'Sullivan committed 69cc09f

Construct bytestrings for scan and takeWhile in one pass.

This saves us a ton of intermediate copies.

Comments (0)

Files changed (1)

Data/Attoparsec/Internal.hs

 -- combinators such as 'many', because such parsers loop until a
 -- failure occurs.  Careless use will thus result in an infinite loop.
 takeWhile :: (Word8 -> Bool) -> Parser B.ByteString
-takeWhile p = go
+takeWhile p = (B.concat . reverse) `fmap` go []
  where
-  go = do
+  go acc = do
     input <- wantInput
     if input
       then do
         (h,t) <- B8.span p <$> get
         put t
         if B.null t
-          then (h+++) `fmapP` go
-          else return h
-      else return B.empty
+          then go (h:acc)
+          else return (h:acc)
+      else return []
 
 -- | A stateful scanner.  The predicate consumes and transforms a
 -- state argument, and each transformed state is passed to successive
 -- combinators such as 'many', because such parsers loop until a
 -- failure occurs.  Careless use will thus result in an infinite loop.
 scan :: s -> (s -> Word8 -> Maybe s) -> Parser B.ByteString
-scan s0 p = go s0
+scan s0 p = (B.concat . reverse) `fmap` go [] s0
  where
-  go s1 = do
+  go acc s1 = do
     input <- wantInput
     if input
       then do
         (h,t,s') <- (unsafePerformIO . scanner) <$> get
         put t
         if B.null t
-          then (h+++) `fmapP` go s'
-          else return h
-      else return B.empty
+          then go (h:acc) s'
+          else return (h:acc)
+      else return acc
 {-# INLINE scan #-}    
 
 -- | Consume input as long as the predicate returns 'True', and return