diff options
Diffstat (limited to 'src/ZNC.hs')
| -rw-r--r-- | src/ZNC.hs | 61 |
1 files changed, 48 insertions, 13 deletions
@@ -2,6 +2,7 @@ module ZNC ( -- Log(..), Nick, Event(..), + preparseLog, parseLog, parseLogRange, ) where @@ -14,15 +15,13 @@ import Data.Char (ord) import Data.Either (fromRight) import Data.Text (Text) import Data.Text.Encoding qualified as TE --- import Data.Vector qualified as V --- import Data.Vector (Vector) -import Data.Word (Word8) +import Data.Vector.Storable qualified as VS +import Data.Word (Word8, Word32) -import Util +import Debug.Trace +import Util --- newtype Log = Log (Vector (TOD, Event)) --- deriving (Show) type Nick = Text @@ -41,20 +40,56 @@ data Event | ParseError deriving (Show) +preparseLog :: ByteString -> VS.Vector Word32 +preparseLog = VS.fromList . findLineStarts 0 + where + findLineStarts :: Int -> ByteString -> [Word32] + findLineStarts off bs = + case BS.findIndex (== 10) (BS.drop off bs) of + Nothing | BS.length bs == off -> [] + | otherwise -> [fromIntegral off] + Just i -> fromIntegral off : findLineStarts (off + i + 1) bs + -- these INLINE/NOINLINE pragmas are optimisation without testing or profiling, have fun {-# INLINE parseLog #-} parseLog :: ByteString -> [(HMS, Event)] -parseLog = parseLogRange (0, Nothing) +parseLog = map parseLogLine . BS8.lines -- (start line, number of lines (default to rest of file)) {-# INLINE parseLogRange #-} -parseLogRange :: (Int, Maybe Int) -> ByteString -> [(HMS, Event)] -parseLogRange (startln, mnumln) = - -- Log . V.fromList . - map go . maybe id take mnumln . drop startln . BS8.lines +parseLogRange :: (Int, Maybe Int) -> VS.Vector Word32 -> ByteString -> [(HMS, Event)] +parseLogRange (startln, mnumln) linestarts topbs = + let numln = maybe (VS.length linestarts - startln) id mnumln + splitted = splitWithLineStarts 0 (VS.slice startln numln linestarts) topbs + in -- traceShow ("pLR"::String, splitted) $ + map parseLogLine splitted where - {-# NOINLINE go #-} - go = fromRight (HMS 0 0 0, ParseError) . P.parseOnly parseLine + {-# INLINE splitWithLineStarts #-} + splitWithLineStarts :: Int -> VS.Vector Word32 -> ByteString -> [ByteString] + splitWithLineStarts idx starts bs + | idx >= VS.length starts = [] + | idx == VS.length starts - 1 = + [BS.takeWhile (\b -> b /= 13 && b /= 10) (BS.drop (at idx) bs)] + | otherwise = + trimCR (BS.drop (at idx) (BS.take (at (idx + 1) - 1) bs)) + : splitWithLineStarts (idx + 1) starts bs + where + at i = fromIntegral @Word32 @Int (starts VS.! i) + + trimCR :: ByteString -> ByteString + trimCR bs = case BS.unsnoc bs of + Just (bs', c) | c == 13 -> bs' + _ -> bs + +parseLogLine :: ByteString -> (HMS, Event) +parseLogLine bs = + case parseLogLine' bs of + res@(HMS 0 0 0, ParseError) -> traceShow ("PE" :: String, bs) res + res -> res + +{-# NOINLINE parseLogLine' #-} +parseLogLine' :: ByteString -> (HMS, Event) +parseLogLine' = fromRight (HMS 0 0 0, ParseError) . P.parseOnly parseLine parseLine :: P.Parser (HMS, Event) parseLine = (,) <$> parseTOD <*> parseEvent |
