1{-# OPTIONS_GHC -fno-warn-name-shadowing #-}
2{-# LANGUAGE BangPatterns, FlexibleInstances, MagicHash, UnboxedTuples #-}
38import Prelude hiding (String, all, any, concat)
39import Data.Binary (Get, get, getWord8, Put, put, putWord8)
40import Data.Binary.Put (putBuilder)
41import Data.Binary.Get.Internal (readN)
42import Data.Bits ((.&.), shiftR)
43import qualified Data.ByteString.Internal as B
44import qualified Data.ByteString.Builder.Internal as B
45import qualified Data.Char as Char
46import qualified Data.List as List
47import Foreign.ForeignPtr (touchForeignPtr)
48import Foreign.ForeignPtr.Unsafe (unsafeForeignPtrToPtr)
49import Foreign.Ptr (minusPtr, plusPtr)
51 ( Int(I#), Ptr(Ptr), Char(C#)
53 , ByteArray#, MutableByteArray#
56 , unsafeFreezeByteArray#
59 , copyAddrToByteArray#
60 , copyByteArrayToAddr#
64import GHC.ST (ST(ST), runST)
66import GHC.Word (Word8(W8#))
68import qualified Parse.Primitives as P
86 runST (freeze =<< newByteArray 0)
89isEmpty :: Utf8 t -> Bool
91 isTrue# (sizeofByteArray# ba# ==# 0#)
100 I# (sizeofByteArray# ba#)
107contains :: Word8 -> Utf8 t -> Bool
108contains (W8# word#) (Utf8 ba#) =
109 containsHelp word# ba# 0# (sizeofByteArray# ba#)
112containsHelp :: Word# -> ByteArray# -> Int# -> Int# -> Bool
113containsHelp word# ba# !offset# len# =
114 if isTrue# (offset# <# len#) then
115 if isTrue# (eqWord# word# (indexWord8Array# ba# offset#))
117 else containsHelp word# ba# (offset# +# 1#) len#
126{-# INLINE startsWith #-}
127startsWith :: Utf8 t -> Utf8 t -> Bool
128startsWith (Utf8 ba1#) (Utf8 ba2#) =
130 !len1# = sizeofByteArray# ba1#
131 !len2# = sizeofByteArray# ba2#
133 isTrue# (len1# <=# len2#)
135 isTrue# (0# ==# compareByteArrays# ba1# 0# ba2# 0# len1#)
142startsWithChar :: (Char -> Bool) -> Utf8 t -> Bool
143startsWithChar isGood bytes@(Utf8 ba#) =
144 if isEmpty bytes then
148 !w# = indexWord8Array# ba# 0#
150 | isTrue# (ltWord# w# 0xC0##) = C# (chr# (word2Int# w#))
151 | isTrue# (ltWord# w# 0xE0##) = chr2 ba# 0# w#
152 | isTrue# (ltWord# w# 0xF0##) = chr3 ba# 0# w#
153 | True = chr4 ba# 0# w#
162endsWithWord8 :: Word8 -> Utf8 t -> Bool
163endsWithWord8 (W8# w#) (Utf8 ba#) =
164 let len# = sizeofByteArray# ba# in
167 isTrue# (eqWord# w# (indexWord8Array# ba# (len# -# 1#)))
174split :: Word8 -> Utf8 t -> [Utf8 t]
175split (W8# divider#) str@(Utf8 ba#) =
176 splitHelp str 0 (findDividers divider# ba# 0# (sizeofByteArray# ba#) [])
179splitHelp :: Utf8 t -> Int -> [Int] -> [Utf8 t]
180splitHelp str start offsets =
183 [ unsafeSlice str start (size str) ]
186 unsafeSlice str start offset : splitHelp str (offset + 1) offsets
189findDividers :: Word# -> ByteArray# -> Int# -> Int# -> [Int] -> [Int]
190findDividers divider# ba# !offset# len# revOffsets =
191 if isTrue# (offset# <# len#) then
192 findDividers divider# ba# (offset# +# 1#) len# $
193 if isTrue# (eqWord# divider# (indexWord8Array# ba# offset#))
194 then I# offset# : revOffsets
200unsafeSlice :: Utf8 t -> Int -> Int -> Utf8 t
201unsafeSlice str start end =
202 let !len = end - start in
207 do mba <- newByteArray len
208 copy str start mba 0 len
216join :: Word8 -> [Utf8 t] -> Utf8 t
224 do let !len = List.foldl' (\w s -> w + 1 + size s) (size str) strs
225 mba <- newByteArray len
226 joinHelp sep mba 0 str strs
230joinHelp :: Word8 -> MBA s -> Int -> Utf8 t -> [Utf8 t] -> ST s ()
231joinHelp sep mba offset str strings =
237 copy str 0 mba offset len
240 do copy str 0 mba offset len
241 let !dotOffset = offset + len
242 writeWord8 mba dotOffset sep
243 let !newOffset = dotOffset + 1
244 joinHelp sep mba newOffset s ss
251instance Eq (Utf8 t) where
252 (==) (Utf8 ba1#) (Utf8 ba2#) =
254 !len1# = sizeofByteArray# ba1#
255 !len2# = sizeofByteArray# ba2#
257 isTrue# (len1# ==# len2#)
259 isTrue# (0# ==# compareByteArrays# ba1# 0# ba2# 0# len1#)
266instance Ord (Utf8 t) where
267 compare (Utf8 ba1#) (Utf8 ba2#) =
269 !len1# = sizeofByteArray# ba1#
270 !len2# = sizeofByteArray# ba2#
271 !len# = if isTrue# (len1# <# len2#) then len1# else len2#
272 !cmp# = compareByteArrays# ba1# 0# ba2# 0# len#
275 _ | isTrue# (cmp# <# 0#) -> LT
276 | isTrue# (cmp# ># 0#) -> GT
277 | isTrue# (len1# <# len2#) -> LT
278 | isTrue# (len1# ># len2#) -> GT
286fromChars :: [Char] -> Utf8 t
290 do mba <- newByteArray (sum (map getWidth chars))
291 writeChars mba 0 chars
295writeChars :: MBA s -> Int -> [Char] -> ST s (Utf8 t)
296writeChars !mba !offset chars =
303 do writeWord8 mba (offset ) (fromIntegral n)
304 writeChars mba (offset + 1) chars
307 do writeWord8 mba (offset ) (fromIntegral ((shiftR n 6 ) + 0xC0))
308 writeWord8 mba (offset + 1) (fromIntegral (( n .&. 0x3F) + 0x80))
309 writeChars mba (offset + 2) chars
312 do writeWord8 mba (offset ) (fromIntegral ((shiftR n 12 ) + 0xE0))
313 writeWord8 mba (offset + 1) (fromIntegral ((shiftR n 6 .&. 0x3F) + 0x80))
314 writeWord8 mba (offset + 2) (fromIntegral (( n .&. 0x3F) + 0x80))
315 writeChars mba (offset + 3) chars
318 do writeWord8 mba (offset ) (fromIntegral ((shiftR n 18 ) + 0xF0))
319 writeWord8 mba (offset + 1) (fromIntegral ((shiftR n 12 .&. 0x3F) + 0x80))
320 writeWord8 mba (offset + 2) (fromIntegral ((shiftR n 6 .&. 0x3F) + 0x80))
321 writeWord8 mba (offset + 3) (fromIntegral (( n .&. 0x3F) + 0x80))
322 writeChars mba (offset + 4) chars
328{-# INLINE getWidth #-}
329getWidth :: Char -> Int
343toChars :: Utf8 t -> [Char]
345 toCharsHelp ba# 0# (sizeofByteArray# ba#)
348toCharsHelp :: ByteArray# -> Int# -> Int# -> [Char]
349toCharsHelp ba# offset# len# =
350 if isTrue# (offset# >=# len#) then
354 !w# = indexWord8Array# ba# offset#
356 | isTrue# (ltWord# w# 0xC0##) = (# C# (chr# (word2Int# w#)), 1# #)
357 | isTrue# (ltWord# w# 0xE0##) = (# chr2 ba# offset# w#, 2# #)
358 | isTrue# (ltWord# w# 0xF0##) = (# chr3 ba# offset# w#, 3# #)
359 | True = (# chr4 ba# offset# w#, 4# #)
361 !newOffset# = offset# +# width#
363 char : toCharsHelp ba# newOffset# len#
367chr2 :: ByteArray# -> Int# -> Word# -> Char
368chr2 ba# offset# firstWord# =
370 !i1# = word2Int# firstWord#
371 !i2# = word2Int# (indexWord8Array# ba# (offset# +# 1#))
372 !c1# = uncheckedIShiftL# (i1# -# 0xC0#) 6#
375 C# (chr# (c1# +# c2#))
379chr3 :: ByteArray# -> Int# -> Word# -> Char
380chr3 ba# offset# firstWord# =
382 !i1# = word2Int# firstWord#
383 !i2# = word2Int# (indexWord8Array# ba# (offset# +# 1#))
384 !i3# = word2Int# (indexWord8Array# ba# (offset# +# 2#))
385 !c1# = uncheckedIShiftL# (i1# -# 0xE0#) 12#
386 !c2# = uncheckedIShiftL# (i2# -# 0x80#) 6#
389 C# (chr# (c1# +# c2# +# c3#))
393chr4 :: ByteArray# -> Int# -> Word# -> Char
394chr4 ba# offset# firstWord# =
396 !i1# = word2Int# firstWord#
397 !i2# = word2Int# (indexWord8Array# ba# (offset# +# 1#))
398 !i3# = word2Int# (indexWord8Array# ba# (offset# +# 2#))
399 !i4# = word2Int# (indexWord8Array# ba# (offset# +# 3#))
400 !c1# = uncheckedIShiftL# (i1# -# 0xF0#) 18#
401 !c2# = uncheckedIShiftL# (i2# -# 0x80#) 12#
402 !c3# = uncheckedIShiftL# (i3# -# 0x80#) 6#
405 C# (chr# (c1# +# c2# +# c3# +# c4#))
412{-# INLINE toBuilder #-}
413toBuilder :: Utf8 t -> B.Builder
415 \bytes -> B.builder (toBuilderHelp bytes)
418{-# INLINE toBuilderHelp #-}
419toBuilderHelp :: Utf8 t -> B.BuildStep a -> B.BuildStep a
420toBuilderHelp !bytes@(Utf8 ba#) k =
421 go 0 (I# (sizeofByteArray# ba#))
423 go !offset !end !(B.BufferRange bOffset bEnd) =
425 !bLen = minusPtr bEnd bOffset
429 do copyToPtr bytes offset bOffset len
430 let !br' = B.BufferRange (plusPtr bOffset len) bEnd
433 do copyToPtr bytes offset bOffset bLen
434 let !offset' = offset + bLen
435 return $ B.bufferFull 1 bEnd (go offset' end)
442{-# INLINE toEscapedBuilder #-}
443toEscapedBuilder :: Word8 -> Word8 -> Utf8 t -> B.Builder
444toEscapedBuilder before after =
445 \name -> B.builder (toEscapedBuilderHelp before after name)
448{-# INLINE toEscapedBuilderHelp #-}
449toEscapedBuilderHelp :: Word8 -> Word8 -> Utf8 t -> B.BuildStep a -> B.BuildStep a
450toEscapedBuilderHelp before after !name@(Utf8 ba#) k =
451 go 0 (I# (sizeofByteArray# ba#))
453 go !offset !len !(B.BufferRange bOffset bEnd) =
455 !bLen = minusPtr bEnd bOffset
458 do -- TODO test if writing word-by-word is faster
459 copyToPtr name offset bOffset len
460 escape before after bOffset name offset len 0
461 let !newBufferRange = B.BufferRange (plusPtr bOffset len) bEnd
464 do copyToPtr name offset bOffset bLen
465 escape before after bOffset name offset bLen 0
466 let !newOffset = offset + bLen
467 let !newLength = len - bLen
468 return $ B.bufferFull 1 bEnd (go newOffset newLength)
471escape :: Word8 -> Word8 -> Ptr a -> Utf8 t -> Int -> Int -> Int -> IO ()
472escape before@(W8# before#) after ptr name@(Utf8 ba#) offset@(I# offset#) len@(I# len#) i@(I# i#) =
473 if isTrue# (i# <# len#) then
474 if isTrue# (eqWord# before# (indexWord8Array# ba# (offset# +# i#)))
476 do writeWordToPtr ptr i after
477 escape before after ptr name offset len (i + 1)
479 do escape before after ptr name offset len (i + 1)
489fromPtr :: Ptr Word8 -> Ptr Word8 -> Utf8 t
491 unsafeDupablePerformIO (stToIO (
492 do let !len = minusPtr end pos
493 mba <- newByteArray len
494 copyFromPtr pos mba 0 len
503fromSnippet :: P.Snippet -> Utf8 t
504fromSnippet (P.Snippet fptr off len _ _) =
505 unsafeDupablePerformIO (stToIO (
506 do mba <- newByteArray len
507 let !pos = plusPtr (unsafeForeignPtrToPtr fptr) off
508 copyFromPtr pos mba 0 len
517putUnder256 :: Utf8 t -> Put
519 do putWord8 (fromIntegral (size bytes))
520 putBuilder (toBuilder bytes)
523getUnder256 :: Get (Utf8 t)
526 let !n = fromIntegral word
527 readN n (copyFromByteString n)
530putVeryLong :: Utf8 t -> Put
533 putBuilder (toBuilder bytes)
536getVeryLong :: Get (Utf8 t)
540 then readN n (copyFromByteString n)
545-- COPY FROM BYTESTRING
548{-# INLINE copyFromByteString #-}
549copyFromByteString :: Int -> B.ByteString -> Utf8 t
550copyFromByteString len (B.PS fptr offset _) =
551 unsafeDupablePerformIO
553 do mba <- stToIO (newByteArray len)
554 stToIO (copyFromPtr (unsafeForeignPtrToPtr fptr `plusPtr` offset) mba 0 len)
565 MBA# (MutableByteArray# s)
568newByteArray :: Int -> ST s (MBA s) -- TODO see if newPinnedByteArray for len > 256 is positive
569newByteArray (I# len#) =
571 case newByteArray# len# s of
572 (# s, mba# #) -> (# s, MBA# mba# #)
575freeze :: MBA s -> ST s (Utf8 t)
578 case unsafeFreezeByteArray# mba# s of
579 (# s, ba# #) -> (# s, Utf8 ba# #)
582copy :: Utf8 t -> Int -> MBA s -> Int -> Int -> ST s ()
583copy (Utf8 ba#) (I# offset#) (MBA# mba#) (I# i#) (I# len#) =
585 case copyByteArray# ba# offset# mba# i# len# s of
589copyFromPtr :: Ptr a -> MBA RealWorld -> Int -> Int -> ST RealWorld ()
590copyFromPtr (Ptr src#) (MBA# mba#) (I# offset#) (I# len#) =
592 case copyAddrToByteArray# src# mba# offset# len# s of
596copyToPtr :: Utf8 t -> Int -> Ptr a -> Int -> IO ()
597copyToPtr (Utf8 ba#) (I# offset#) (Ptr mba#) (I# len#) =
599 case copyByteArrayToAddr# ba# offset# mba# len# s of
603{-# INLINE writeWord8 #-}
604writeWord8 :: MBA s -> Int -> Word8 -> ST s ()
605writeWord8 (MBA# mba#) (I# offset#) (W8# w#) =
607 case writeWord8Array# mba# offset# w# s of
611{-# INLINE writeWordToPtr #-}
612writeWordToPtr :: Ptr a -> Int -> Word8 -> IO ()
613writeWordToPtr (Ptr addr#) (I# offset#) (W8# word#) =
615 case writeWord8OffAddr# addr# offset# word# s of
keysesc to close
- j k
- move down, up
- enter
- open
- esc
- back, or up a level
- 1 2 3 4
- readme, files, commits, refs
- /
- filter
- y
- copy the clone command
- c
- compare the chosen commit with another (or shift-click both)
- ?
- show or hide this list