on master help sign in
1 file changed+41−16
since splitsnapshots
unifiedsplit
Data/Aeson/Parser/Internal.hs+41−16
Data/Aeson/Parser/Internal.hs+41−16
@@ -2,9 +2,12 @@
22{-# LANGUAGE CPP #-}
33{-# LANGUAGE NoImplicitPrelude #-}
44{-# LANGUAGE OverloadedStrings #-}
5+#if MIN_VERSION_ghc_prim(0,3,1)
6+{-# LANGUAGE MagicHash #-}
7+#endif
58#if __GLASGOW_HASKELL__ <= 710 && __GLASGOW_HASKELL__ >= 706
69-- Work around a compiler bug
7−{-# OPTIONS_GHC -fsimpl-tick-factor=300 #-}
10+{-# OPTIONS_GHC -fsimpl-tick-factor=200 #-}
811#endif
912-- |
1013-- Module: Data.Aeson.Parser.Internal
@@ -55,10 +58,8 @@ import Data.Aeson.Types.Internal (IResult(..), JSONPath, Object, Result(..), Val
5558import Data.Attoparsec.ByteString.Char8 (Parser, char, decimal, endOfInput, isDigit_w8, signed, string)
5659import Data.Function (fix)
5760import Data.Functor.Compat (($>))
58−import Data.Bits (testBit)
5961import Data.Scientific (Scientific)
6062import Data.Text (Text)
61−import qualified Data.Text.Encoding as TE
6263import Data.Vector (Vector)
6364import qualified Data.Vector as Vector (empty, fromList, fromListN, reverse)
6465import qualified Data.Attoparsec.ByteString as A
@@ -70,6 +71,12 @@ import qualified Data.HashMap.Strict as H
7071import qualified Data.Scientific as Sci
7172import Data.Aeson.Parser.Unescape (unescapeText)
7273
74+#if MIN_VERSION_ghc_prim(0,3,1)
75+import GHC.Base (Int#, (==#), isTrue#, word2Int#, orI#, andI#)
76+import GHC.Word (Word8(W8#))
77+import qualified Data.Text.Encoding as TE
78+#endif
79+
7380#define BACKSLASH 92
7481#define CLOSE_CURLY 125
7582#define CLOSE_SQUARE 93
@@ -316,20 +323,37 @@ jstring = A.word8 DOUBLE_QUOTE *> jstring_
316323-- | Parse a string without a leading quote.
317324jstring_ :: Parser Text
318325{-# INLINE jstring_ #-}
319−jstring_ = do
320− s <- A.takeWhile (\w -> w /= DOUBLE_QUOTE && w /= BACKSLASH && not (testBit w 7))
321− let txt = TE.decodeUtf8 s
322− w <- A.peekWord8
323− case w of
324− Nothing -> fail "string without end"
325− Just DOUBLE_QUOTE -> A.anyWord8 $> txt
326− _ -> jstringSlow s
327−
328−jstringSlow :: B.ByteString -> Parser Text
329−{-# INLINE jstringSlow #-}
330−jstringSlow s' = {-# SCC "jstringSlow" #-} do
326+jstring_ = {-# SCC "jstring_" #-} do
327+#if MIN_VERSION_ghc_prim(0,3,1)
328+ (s, S _ escaped) <- A.runScanner startState go <* A.anyWord8
329+ -- We escape only if there are
330+ -- non-ascii (over 7bit) characters or backslash present.
331+ --
332+ -- Note: if/when text will have fast ascii -> text conversion
333+ -- (e.g. uses utf8 encoding) we can have further speedup.
334+ if isTrue# escaped
335+ then case unescapeText s of
336+ Right r -> return r
337+ Left err -> fail $ show err
338+ else return (TE.decodeUtf8 s)
339+ where
340+ startState = S 0# 0#
341+ go (S skip escaped) (W8# c)
342+ | isTrue# skip = Just (S 0# escaped')
343+ | isTrue# (w ==# 34#) = Nothing -- double quote
344+ | otherwise = Just (S skip' escaped')
345+ where
346+ w = word2Int# c
347+ skip' = w ==# 92# -- backslash
348+ escaped' = escaped
349+ `orI#` (w `andI#` 0x80# ==# 0x80#) -- c >= 0x80
350+ `orI#` skip'
351+ `orI#` (w `andI#` 0x1f# ==# w) -- c < 0x20
352+
353+data S = S Int# Int#
354+#else
331355 s <- A.scan startState go <* A.anyWord8
332− case unescapeText (B.append s' s) of
356+ case unescapeText s of
333357 Right r -> return r
334358 Left err -> fail $ show err
335359 where
@@ -340,6 +364,7 @@ jstringSlow s' = {-# SCC "jstringSlow" #-} do
340364 | otherwise = let a' = c == backslash
341365 in Just a'
342366 where backslash = BACKSLASH
367+#endif
343368
344369decodeWith :: Parser Value -> (Value -> Result a) -> L.ByteString -> Maybe a
345370decodeWith p to s =