summaryrefslogtreecommitdiff
path: root/compiler/utils
diff options
context:
space:
mode:
authoralexbiehl <alex.biehl@gmail.com>2017-04-17 12:51:10 -0400
committerBen Gamari <ben@smart-cactus.org>2017-04-17 20:34:40 -0400
commit065be6e9eb5114c5f0e3a20626ec93042ce47f13 (patch)
tree130e3c1434db9ae0d24a873c1f110422c034ba4b /compiler/utils
parentc87584f167ae6aee7b75d6ee4a39586b291543a0 (diff)
downloadhaskell-065be6e9eb5114c5f0e3a20626ec93042ce47f13.tar.gz
Caret diag.: Avoid decoding whole module if only specific line is needed
Before we were decoding the whole file to get to the desired line. This patch introduces a fast function which searches a StringBuffer for the desired line so we only need to utf8 decode a little portion. This is especially interesting if we have big modules with lots of warnings. Reviewers: austin, bgamari, Rufflewind, trofi Reviewed By: Rufflewind, trofi Subscribers: rwbarton, thomie Differential Revision: https://phabricator.haskell.org/D3440
Diffstat (limited to 'compiler/utils')
-rw-r--r--compiler/utils/StringBuffer.hs40
1 files changed, 39 insertions, 1 deletions
diff --git a/compiler/utils/StringBuffer.hs b/compiler/utils/StringBuffer.hs
index fcc344554b..d75e537fca 100644
--- a/compiler/utils/StringBuffer.hs
+++ b/compiler/utils/StringBuffer.hs
@@ -6,7 +6,7 @@
Buffers for scanning string input stored in external arrays.
-}
-{-# LANGUAGE CPP, MagicHash, UnboxedTuples #-}
+{-# LANGUAGE BangPatterns, CPP, MagicHash, UnboxedTuples #-}
{-# OPTIONS_GHC -O #-}
-- We always optimise this, otherwise performance of a non-optimised
-- compiler is severely affected
@@ -32,6 +32,7 @@ module StringBuffer
stepOn,
offsetBytes,
byteDiff,
+ atLine,
-- * Conversion
lexemeToString,
@@ -240,6 +241,43 @@ byteDiff s1 s2 = cur s2 - cur s1
atEnd :: StringBuffer -> Bool
atEnd (StringBuffer _ l c) = l == c
+-- | Computes a 'StringBuffer' which points to the first character of the
+-- wanted line. Lines begin at 1.
+atLine :: Int -> StringBuffer -> Maybe StringBuffer
+atLine line sb@(StringBuffer buf len _) =
+ inlinePerformIO $
+ withForeignPtr buf $ \p -> do
+ p' <- skipToLine line len p
+ if p' == nullPtr
+ then return Nothing
+ else
+ let
+ delta = p' `minusPtr` p
+ in return $ Just (sb { cur = delta
+ , len = len - delta
+ })
+
+skipToLine :: Int -> Int -> Ptr Word8 -> IO (Ptr Word8)
+skipToLine !line !len !op0 = go 1 op0
+ where
+ !opend = op0 `plusPtr` len
+
+ go !i_line !op
+ | op >= opend = pure nullPtr
+ | i_line == line = pure op
+ | otherwise = do
+ w <- peek op :: IO Word8
+ case w of
+ 10 -> go (i_line + 1) (plusPtr op 1)
+ 13 -> do
+ -- this is safe because a 'StringBuffer' is
+ -- guaranteed to have 3 bytes sentinel values.
+ w' <- peek (plusPtr op 1) :: IO Word8
+ case w' of
+ 10 -> go (i_line + 1) (plusPtr op 2)
+ _ -> go (i_line + 1) (plusPtr op 1)
+ _ -> go i_line (plusPtr op 1)
+
-- -----------------------------------------------------------------------------
-- Conversion