@@ -0,0 +1,215 @@
1+{-# OPTIONS_GHC -fno-warn-name-shadowing #-}
2+{-# LANGUAGE BangPatterns, MagicHash, UnboxedTuples #-}
12+import Data.Bits ((.&.), shiftR)
13+import qualified Data.ByteString.Builder.Internal as B
14+import Foreign.ForeignPtr (ForeignPtr, touchForeignPtr)
15+import Foreign.ForeignPtr.Unsafe (unsafeForeignPtrToPtr)
16+import Foreign.Ptr (minusPtr, plusPtr)
20+ , ByteArray#, MutableByteArray#
22+ , newByteArray#, unsafeFreezeByteArray#
24+ , copyAddrToByteArray#, copyByteArrayToAddr#
25+ , writeWord8Array#, writeWord16Array#
28+import GHC.ST (ST(ST))
30+import GHC.Word (Word8(W8#), Word16(W16#))
45+instance Eq Utf8 where
46+ (==) (Utf8 ba1#) (Utf8 ba2#) =
48+ !len1# = sizeofByteArray# ba1#
49+ !len2# = sizeofByteArray# ba2#
51+ isTrue# (len1# ==# len2#)
53+ isTrue# (0# ==# compareByteArrays# ba1# 0# ba2# 0# len1#)
61+ = Slice Int Int -- TODO try UNPACK
66+fromChunks :: ForeignPtr Word8 -> [Chunk] -> Utf8
67+fromChunks fptr chunks =
68+ unsafeDupablePerformIO
70+ do let !len = sum (map chunkToWidth chunks)
71+ mba <- stToIO (newByteArray len)
72+ stToIO (writeChunks (unsafeForeignPtrToPtr fptr) mba 0 chunks)
74+ stToIO (unsafeFreeze mba)
78+chunkToWidth :: Chunk -> Int
88+ if code < 0xFFFF then 6 else 12
91+writeChunks :: Ptr Word8 -> MBA RealWorld -> Int -> [Chunk] -> ST RealWorld ()
92+writeChunks ptr mba offset chunks =
100+ do copyFromPtr (plusPtr ptr off) mba offset len
101+ let !newOffset = offset + len
102+ writeChunks ptr mba newOffset chunks
105+ do writeWord16 mba offset word
106+ let !newOffset = offset + 2
107+ writeChunks ptr mba newOffset chunks
110+ if code < 0xFFFF then
111+ do writeCode mba offset code
112+ let !newOffset = offset + 6
113+ writeChunks ptr mba newOffset chunks
115+ do let (hi,lo) = divMod (code - 0x10000) 0x400
116+ writeCode mba (offset ) (hi + 0xD800)
117+ writeCode mba (offset + 6) (lo + 0xDC00)
118+ let !newOffset = offset + 12
119+ writeChunks ptr mba newOffset chunks
122+-- TODO see if it is faster to writeWord32 a block of hex-as-ascii
123+writeCode :: MBA RealWorld -> Int -> Int -> ST RealWorld ()
124+writeCode mba offset code =
125+ do writeWord16 mba offset 0x5C75 {- \u -}
126+ writeHex mba (offset + 2) (shiftR code 12)
127+ writeHex mba (offset + 3) (shiftR code 8)
128+ writeHex mba (offset + 4) (shiftR code 4)
129+ writeHex mba (offset + 5) code
132+writeHex :: MBA RealWorld -> Int -> Int -> ST RealWorld ()
133+writeHex mba !offset !bits =
134+ do let !n = fromIntegral bits .&. 0x0F
135+ writeWord8 mba offset (if n < 10 then 0x30 + n else 0x37 + n)
142+{-# INLINE toBuilder #-}
143+toBuilder :: Utf8 -> B.Builder
145+ \utf8 -> B.builder (toBuilderHelp utf8)
148+{-# INLINE toBuilderHelp #-}
149+toBuilderHelp :: Utf8 -> B.BuildStep a -> B.BuildStep a
150+toBuilderHelp !utf8@(Utf8 ba#) k =
151+ go 0 (I# (sizeofByteArray# ba#))
153+ go !offset !end !(B.BufferRange bOffset bEnd) =
155+ !bLen = minusPtr bEnd bOffset
159+ do stToIO (copyToPtr utf8 offset bOffset len)
160+ let !br' = B.BufferRange (plusPtr bOffset len) bEnd
163+ do stToIO (copyToPtr utf8 offset bOffset bLen)
164+ let !offset' = offset + bLen
165+ return $ B.bufferFull 1 bEnd (go offset' end)
173+ MBA# (MutableByteArray# s)
176+newByteArray :: Int -> ST s (MBA s)
177+newByteArray (I# len#) =
179+ case newByteArray# len# s of
180+ (# s, mba# #) -> (# s, MBA# mba# #)
183+unsafeFreeze :: MBA s -> ST s Utf8
184+unsafeFreeze (MBA# mba#) =
186+ case unsafeFreezeByteArray# mba# s of
187+ (# s, ba# #) -> (# s, Utf8 ba# #)
190+copyFromPtr :: Ptr a -> MBA RealWorld -> Int -> Int -> ST RealWorld ()
191+copyFromPtr (Ptr src#) (MBA# mba#) (I# dst_off#) (I# len#) =
193+ case copyAddrToByteArray# src# mba# dst_off# len# s of
197+copyToPtr :: Utf8 -> Int -> Ptr a -> Int -> ST RealWorld ()
198+copyToPtr (Utf8 ba#) (I# offset#) (Ptr mba#) (I# len#) =
200+ case copyByteArrayToAddr# ba# offset# mba# len# s of
204+writeWord8 :: MBA s -> Int -> Word8 -> ST s ()
205+writeWord8 (MBA# mba#) (I# i#) (W8# w#) =
207+ case writeWord8Array# mba# i# w# s of
211+writeWord16 :: MBA s -> Int -> Word16 -> ST s ()
212+writeWord16 (MBA# mba#) (I# i#) (W16# w#) =
214+ case writeWord16Array# mba# i# w# s of