{-# OPTIONS_GHC -O2 #-}
{-# LANGUAGE MagicHash #-}
{-# LANGUAGE UnboxedTuples #-}
module Hmssql.Tds.Utf16
( encodeUtf16LE
, utf16Length
, unsafeWriteUtf16LE
, utf16LEBuilder
, decodeUtf16LE
, decodeUtf16Chunks
) where
import Streaming (Stream, Of)
import qualified Streaming as S
import qualified Streaming.Prelude as S
import Control.Monad.ST (RealWorld, stToIO)
import Data.Array.Byte (MutableByteArray (..))
import Data.Bits (shiftL, shiftR, unsafeShiftL, unsafeShiftR, (.&.), (.|.))
import qualified Data.ByteString as B
import qualified Data.ByteString.Builder as BB
import qualified Data.ByteString.Builder.Internal as BBI
import qualified Data.ByteString.Internal as BI
import qualified Data.Text as T
import Data.Text.Internal (Text (..))
import qualified Data.Text.Array as A
import Data.Word (Word16, Word32, Word64, Word8)
import Foreign.ForeignPtr (withForeignPtr)
import Foreign.Ptr (Ptr, minusPtr, plusPtr)
import Foreign.Storable (peekByteOff, pokeByteOff)
import GHC.ByteOrder (ByteOrder (..), targetByteOrder)
import GHC.Exts (Int (..), indexWord8ArrayAsWord64#, writeWord8ArrayAsWord32#, writeWord8ArrayAsWord64#)
import GHC.IO (IO (..))
import GHC.Word (Word32 (..), Word64 (..))
import System.IO.Unsafe (unsafeDupablePerformIO)
import Hmssql.Tds.Bytes.Unsafe (peekWord16LE, peekWord64LE, pokeWord64LE)
encodeUtf16LE :: Text -> B.ByteString
encodeUtf16LE :: Text -> ByteString
encodeUtf16LE t :: Text
t@(Text Array
_ Int
_ Int
len)
| Int
len Int -> Int -> Bool
forall a. Eq a => a -> a -> Bool
== Int
0 = ByteString
B.empty
| Bool
otherwise = IO ByteString -> ByteString
forall a. IO a -> a
unsafeDupablePerformIO (IO ByteString -> ByteString) -> IO ByteString -> ByteString
forall a b. (a -> b) -> a -> b
$ do
fp <- Int -> IO (ForeignPtr Word8)
forall a. Int -> IO (ForeignPtr a)
BI.mallocByteString (Int
2 Int -> Int -> Int
forall a. Num a => a -> a -> a
* Int
len)
n <- withForeignPtr fp (unsafeWriteUtf16LE t)
pure $! if n == 2 * len then BI.BS fp n else B.copy (BI.BS fp n)
{-# NOINLINE encodeUtf16LE #-}
utf16LEBuilder :: Text -> BB.Builder
utf16LEBuilder :: Text -> Builder
utf16LEBuilder t :: Text
t@(Text Array
_ Int
_ Int
len)
| Int
len Int -> Int -> Bool
forall a. Eq a => a -> a -> Bool
== Int
0 = Builder
forall a. Monoid a => a
mempty
| Int
len Int -> Int -> Bool
forall a. Ord a => a -> a -> Bool
> Int
16376 = let (Text
here, Text
rest) = Int -> Text -> (Text, Text)
T.splitAt Int
2048 Text
t in Text -> Builder
utf16LEBuilder Text
here Builder -> Builder -> Builder
forall a. Semigroup a => a -> a -> a
<> Text -> Builder
utf16LEBuilder Text
rest
| Bool
otherwise = (forall r. BuildStep r -> BuildStep r) -> Builder
BBI.builder BuildStep r -> BuildStep r
forall r. BuildStep r -> BuildStep r
step
where
step :: BBI.BuildStep r -> BBI.BuildStep r
step :: forall r. BuildStep r -> BuildStep r
step BuildStep r
k (BBI.BufferRange Ptr Word8
op Ptr Word8
ope)
| Ptr Word8
ope Ptr Word8 -> Ptr Word8 -> Int
forall a b. Ptr a -> Ptr b -> Int
`minusPtr` Ptr Word8
op Int -> Int -> Bool
forall a. Ord a => a -> a -> Bool
>= Int
2 Int -> Int -> Int
forall a. Num a => a -> a -> a
* Int
len = do
n <- Text -> Ptr Word8 -> IO Int
unsafeWriteUtf16LE Text
t Ptr Word8
op
k (BBI.BufferRange (op `plusPtr` n) ope)
| Bool
otherwise = BuildSignal r -> IO (BuildSignal r)
forall a. a -> IO a
forall (f :: * -> *) a. Applicative f => a -> f a
pure (Int -> Ptr Word8 -> BuildStep r -> BuildSignal r
forall a. Int -> Ptr Word8 -> BuildStep a -> BuildSignal a
BBI.bufferFull (Int
2 Int -> Int -> Int
forall a. Num a => a -> a -> a
* Int
len) Ptr Word8
op (BuildStep r -> BuildStep r
forall r. BuildStep r -> BuildStep r
step BuildStep r
k))
utf16Length :: Text -> Int
utf16Length :: Text -> Int
utf16Length (Text Array
arr Int
off Int
len) = Int -> Int -> Int
forall {t}. Num t => Int -> t -> t
go Int
off Int
0
where
end :: Int
end = Int
off Int -> Int -> Int
forall a. Num a => a -> a -> a
+ Int
len
go :: Int -> t -> t
go !Int
i !t
n
| Int
i Int -> Int -> Bool
forall a. Ord a => a -> a -> Bool
>= Int
end = t
n
| Bool
otherwise =
let b :: Word8
b = Array -> Int -> Word8
A.unsafeIndex Array
arr Int
i
in Int -> t -> t
go (Int
i Int -> Int -> Int
forall a. Num a => a -> a -> a
+ Int
1) (t
n t -> t -> t
forall a. Num a => a -> a -> a
+ (if Word8
b Word8 -> Word8 -> Word8
forall a. Bits a => a -> a -> a
.&. Word8
0xC0 Word8 -> Word8 -> Bool
forall a. Eq a => a -> a -> Bool
/= Word8
0x80 then t
1 else t
0) t -> t -> t
forall a. Num a => a -> a -> a
+ (if Word8
b Word8 -> Word8 -> Bool
forall a. Ord a => a -> a -> Bool
>= Word8
0xF0 then t
1 else t
0))
unsafeWriteUtf16LE :: Text -> Ptr Word8 -> IO Int
unsafeWriteUtf16LE :: Text -> Ptr Word8 -> IO Int
unsafeWriteUtf16LE (Text Array
arr Int
off Int
len) Ptr Word8
p = Int -> Int -> IO Int
go Int
off Int
0
where
end :: Int
end = Int
off Int -> Int -> Int
forall a. Num a => a -> a -> a
+ Int
len
go :: Int -> Int -> IO Int
go !Int
i !Int
o
| ByteOrder
targetByteOrder ByteOrder -> ByteOrder -> Bool
forall a. Eq a => a -> a -> Bool
== ByteOrder
LittleEndian, Int
i Int -> Int -> Int
forall a. Num a => a -> a -> a
+ Int
8 Int -> Int -> Bool
forall a. Ord a => a -> a -> Bool
<= Int
end, Word64 -> Bool
forall {a}. (Bits a, Num a) => a -> Bool
ascii8 Word64
w = do
Ptr Word8 -> Int -> Word64 -> IO ()
pokeWord64LE Ptr Word8
p Int
o (Word64 -> Word64
spread Word64
w)
Ptr Word8 -> Int -> Word64 -> IO ()
pokeWord64LE Ptr Word8
p (Int
o Int -> Int -> Int
forall a. Num a => a -> a -> a
+ Int
8) (Word64 -> Word64
spread (Word64
w Word64 -> Int -> Word64
forall a. Bits a => a -> Int -> a
`unsafeShiftR` Int
32))
Int -> Int -> IO Int
go (Int
i Int -> Int -> Int
forall a. Num a => a -> a -> a
+ Int
8) (Int
o Int -> Int -> Int
forall a. Num a => a -> a -> a
+ Int
16)
| Int
i Int -> Int -> Bool
forall a. Ord a => a -> a -> Bool
>= Int
end = Int -> IO Int
forall a. a -> IO a
forall (f :: * -> *) a. Applicative f => a -> f a
pure Int
o
| Word8
b Word8 -> Word8 -> Bool
forall a. Ord a => a -> a -> Bool
< Word8
0x80 = Int -> Word16 -> IO ()
unit Int
o (Word8 -> Word16
forall a b. (Integral a, Num b) => a -> b
fromIntegral Word8
b) IO () -> IO Int -> IO Int
forall a b. IO a -> IO b -> IO b
forall (m :: * -> *) a b. Monad m => m a -> m b -> m b
>> Int -> Int -> IO Int
go (Int
i Int -> Int -> Int
forall a. Num a => a -> a -> a
+ Int
1) (Int
o Int -> Int -> Int
forall a. Num a => a -> a -> a
+ Int
2)
| Word8
b Word8 -> Word8 -> Bool
forall a. Ord a => a -> a -> Bool
< Word8
0xE0 = do
Int -> Word16 -> IO ()
unit Int
o ((Word8 -> Word16
forall a b. (Integral a, Num b) => a -> b
fromIntegral (Word8
b Word8 -> Word8 -> Word8
forall a. Bits a => a -> a -> a
.&. Word8
0x1F) Word16 -> Int -> Word16
forall a. Bits a => a -> Int -> a
`shiftL` Int
6) Word16 -> Word16 -> Word16
forall a. Bits a => a -> a -> a
.|. Int -> Word16
cont Int
1)
Int -> Int -> IO Int
go (Int
i Int -> Int -> Int
forall a. Num a => a -> a -> a
+ Int
2) (Int
o Int -> Int -> Int
forall a. Num a => a -> a -> a
+ Int
2)
| Word8
b Word8 -> Word8 -> Bool
forall a. Ord a => a -> a -> Bool
< Word8
0xF0 = do
Int -> Word16 -> IO ()
unit Int
o ((Word8 -> Word16
forall a b. (Integral a, Num b) => a -> b
fromIntegral (Word8
b Word8 -> Word8 -> Word8
forall a. Bits a => a -> a -> a
.&. Word8
0x0F) Word16 -> Int -> Word16
forall a. Bits a => a -> Int -> a
`shiftL` Int
12) Word16 -> Word16 -> Word16
forall a. Bits a => a -> a -> a
.|. (Int -> Word16
cont Int
1 Word16 -> Int -> Word16
forall a. Bits a => a -> Int -> a
`shiftL` Int
6) Word16 -> Word16 -> Word16
forall a. Bits a => a -> a -> a
.|. Int -> Word16
cont Int
2)
Int -> Int -> IO Int
go (Int
i Int -> Int -> Int
forall a. Num a => a -> a -> a
+ Int
3) (Int
o Int -> Int -> Int
forall a. Num a => a -> a -> a
+ Int
2)
| Bool
otherwise = do
let c :: Int
c = ((Word8 -> Int
forall a b. (Integral a, Num b) => a -> b
fromIntegral (Word8
b Word8 -> Word8 -> Word8
forall a. Bits a => a -> a -> a
.&. Word8
0x07) :: Int) Int -> Int -> Int
forall a. Bits a => a -> Int -> a
`shiftL` Int
18)
Int -> Int -> Int
forall a. Bits a => a -> a -> a
.|. (Word16 -> Int
forall a b. (Integral a, Num b) => a -> b
fromIntegral (Int -> Word16
cont Int
1) Int -> Int -> Int
forall a. Bits a => a -> Int -> a
`shiftL` Int
12) Int -> Int -> Int
forall a. Bits a => a -> a -> a
.|. (Word16 -> Int
forall a b. (Integral a, Num b) => a -> b
fromIntegral (Int -> Word16
cont Int
2) Int -> Int -> Int
forall a. Bits a => a -> Int -> a
`shiftL` Int
6)
Int -> Int -> Int
forall a. Bits a => a -> a -> a
.|. Word16 -> Int
forall a b. (Integral a, Num b) => a -> b
fromIntegral (Int -> Word16
cont Int
3)
c' :: Int
c' = Int
c Int -> Int -> Int
forall a. Num a => a -> a -> a
- Int
0x10000
Int -> Word16 -> IO ()
unit Int
o (Int -> Word16
forall a b. (Integral a, Num b) => a -> b
fromIntegral (Int
0xD800 Int -> Int -> Int
forall a. Num a => a -> a -> a
+ (Int
c' Int -> Int -> Int
forall a. Bits a => a -> Int -> a
`shiftR` Int
10)))
Int -> Word16 -> IO ()
unit (Int
o Int -> Int -> Int
forall a. Num a => a -> a -> a
+ Int
2) (Int -> Word16
forall a b. (Integral a, Num b) => a -> b
fromIntegral (Int
0xDC00 Int -> Int -> Int
forall a. Num a => a -> a -> a
+ (Int
c' Int -> Int -> Int
forall a. Bits a => a -> a -> a
.&. Int
0x3FF)))
Int -> Int -> IO Int
go (Int
i Int -> Int -> Int
forall a. Num a => a -> a -> a
+ Int
4) (Int
o Int -> Int -> Int
forall a. Num a => a -> a -> a
+ Int
4)
where
b :: Word8
b = Array -> Int -> Word8
A.unsafeIndex Array
arr Int
i
w :: Word64
w = Int -> Word64
word64At (Int
i :: Int)
cont :: Int -> Word16
cont :: Int -> Word16
cont Int
k = Word8 -> Word16
forall a b. (Integral a, Num b) => a -> b
fromIntegral (Array -> Int -> Word8
A.unsafeIndex Array
arr (Int
i Int -> Int -> Int
forall a. Num a => a -> a -> a
+ Int
k) Word8 -> Word8 -> Word8
forall a. Bits a => a -> a -> a
.&. Word8
0x3F)
unit :: Int -> Word16 -> IO ()
unit :: Int -> Word16 -> IO ()
unit Int
o Word16
u = do
Ptr Word8 -> Int -> Word8 -> IO ()
forall b. Ptr b -> Int -> Word8 -> IO ()
forall a b. Storable a => Ptr b -> Int -> a -> IO ()
pokeByteOff Ptr Word8
p Int
o (Word16 -> Word8
forall a b. (Integral a, Num b) => a -> b
fromIntegral Word16
u :: Word8)
Ptr Word8 -> Int -> Word8 -> IO ()
forall b. Ptr b -> Int -> Word8 -> IO ()
forall a b. Storable a => Ptr b -> Int -> a -> IO ()
pokeByteOff Ptr Word8
p (Int
o Int -> Int -> Int
forall a. Num a => a -> a -> a
+ Int
1) (Word16 -> Word8
forall a b. (Integral a, Num b) => a -> b
fromIntegral (Word16
u Word16 -> Int -> Word16
forall a. Bits a => a -> Int -> a
`unsafeShiftR` Int
8) :: Word8)
ascii8 :: a -> Bool
ascii8 a
x = a
x a -> a -> a
forall a. Bits a => a -> a -> a
.&. a
0x8080808080808080 a -> a -> Bool
forall a. Eq a => a -> a -> Bool
== a
0
spread :: Word64 -> Word64
spread :: Word64 -> Word64
spread Word64
x0 =
let x1 :: Word64
x1 = Word64
x0 Word64 -> Word64 -> Word64
forall a. Bits a => a -> a -> a
.&. Word64
0xFFFFFFFF
x2 :: Word64
x2 = (Word64
x1 Word64 -> Word64 -> Word64
forall a. Bits a => a -> a -> a
.|. (Word64
x1 Word64 -> Int -> Word64
forall a. Bits a => a -> Int -> a
`unsafeShiftL` Int
16)) Word64 -> Word64 -> Word64
forall a. Bits a => a -> a -> a
.&. Word64
0x0000FFFF0000FFFF
in (Word64
x2 Word64 -> Word64 -> Word64
forall a. Bits a => a -> a -> a
.|. (Word64
x2 Word64 -> Int -> Word64
forall a. Bits a => a -> Int -> a
`unsafeShiftL` Int
8)) Word64 -> Word64 -> Word64
forall a. Bits a => a -> a -> a
.&. Word64
0x00FF00FF00FF00FF
word64At :: Int -> Word64
word64At (I# Int#
i) = case Array
arr of
A.ByteArray ByteArray#
ba -> Word64# -> Word64
W64# (ByteArray# -> Int# -> Word64#
indexWord8ArrayAsWord64# ByteArray#
ba Int#
i)
decodeUtf16LE :: B.ByteString -> Text
decodeUtf16LE :: ByteString -> Text
decodeUtf16LE (BI.BS ForeignPtr Word8
fp Int
len)
| Int
len Int -> Int -> Bool
forall a. Ord a => a -> a -> Bool
<= Int
0 = Text
T.empty
| Bool
otherwise = IO Text -> Text
forall a. IO a -> a
unsafeDupablePerformIO (IO Text -> Text) -> IO Text -> Text
forall a b. (a -> b) -> a -> b
$ ForeignPtr Word8 -> (Ptr Word8 -> IO Text) -> IO Text
forall a b. ForeignPtr a -> (Ptr a -> IO b) -> IO b
withForeignPtr ForeignPtr Word8
fp ((Ptr Word8 -> IO Text) -> IO Text)
-> (Ptr Word8 -> IO Text) -> IO Text
forall a b. (a -> b) -> a -> b
$ \Ptr Word8
p -> do
let units :: Int
units = Int
len Int -> Int -> Int
forall a. Bits a => a -> Int -> a
`unsafeShiftR` Int
1
startsAscii <-
if Int
len Int -> Int -> Bool
forall a. Ord a => a -> a -> Bool
>= Int
2
then (\Word8
b1 Word8
b0 -> Word8
b1 Word8 -> Word8 -> Bool
forall a. Eq a => a -> a -> Bool
== (Word8
0 :: Word8) Bool -> Bool -> Bool
&& Word8
b0 Word8 -> Word8 -> Bool
forall a. Ord a => a -> a -> Bool
< (Word8
0x80 :: Word8)) (Word8 -> Word8 -> Bool) -> IO Word8 -> IO (Word8 -> Bool)
forall (f :: * -> *) a b. Functor f => (a -> b) -> f a -> f b
<$> Ptr Word8 -> Int -> IO Word8
forall b. Ptr b -> Int -> IO Word8
forall a b. Storable a => Ptr b -> Int -> IO a
peekByteOff Ptr Word8
p Int
1 IO (Word8 -> Bool) -> IO Word8 -> IO Bool
forall a b. IO (a -> b) -> IO a -> IO b
forall (f :: * -> *) a b. Applicative f => f (a -> b) -> f a -> f b
<*> Ptr Word8 -> Int -> IO Word8
forall b. Ptr b -> Int -> IO Word8
forall a b. Storable a => Ptr b -> Int -> IO a
peekByteOff Ptr Word8
p Int
0
else Bool -> IO Bool
forall a. a -> IO a
forall (f :: * -> *) a. Applicative f => a -> f a
pure Bool
False
let cap0 = if Bool
startsAscii then Int
units else Int -> Int -> Int
maxLength Int
0 Int
len
marr0 <- stToIO (A.new cap0)
(marr, cap, n) <- decodeInto p len marr0 cap0
arr <- stToIO $ if
| n == cap -> A.unsafeFreeze marr
| cap > 4096 && cap - n > cap `unsafeShiftR` 3 -> do
exact <- A.new n
A.copyM exact 0 marr 0 n
A.unsafeFreeze exact
| otherwise -> A.shrinkM marr n >> A.unsafeFreeze marr
pure (Text arr 0 n)
decodeUtf16Chunks :: Monad m => Stream (Of B.ByteString) m r -> Stream (Of T.Text) m r
decodeUtf16Chunks :: forall (m :: * -> *) r.
Monad m =>
Stream (Of ByteString) m r -> Stream (Of Text) m r
decodeUtf16Chunks = ByteString -> Stream (Of ByteString) m r -> Stream (Of Text) m r
forall {m :: * -> *} {r}.
Monad m =>
ByteString -> Stream (Of ByteString) m r -> Stream (Of Text) m r
go ByteString
B.empty
where
go :: ByteString -> Stream (Of ByteString) m r -> Stream (Of Text) m r
go ByteString
carry Stream (Of ByteString) m r
source = m (Stream (Of Text) m r) -> Stream (Of Text) m r
forall (m :: * -> *) (f :: * -> *) r.
(Monad m, Functor f) =>
m (Stream f m r) -> Stream f m r
S.effect (m (Stream (Of Text) m r) -> Stream (Of Text) m r)
-> m (Stream (Of Text) m r) -> Stream (Of Text) m r
forall a b. (a -> b) -> a -> b
$ Stream (Of ByteString) m r
-> m (Either r (ByteString, Stream (Of ByteString) m r))
forall (m :: * -> *) a r.
Monad m =>
Stream (Of a) m r -> m (Either r (a, Stream (Of a) m r))
S.next Stream (Of ByteString) m r
source m (Either r (ByteString, Stream (Of ByteString) m r))
-> (Either r (ByteString, Stream (Of ByteString) m r)
-> m (Stream (Of Text) m r))
-> m (Stream (Of Text) m r)
forall a b. m a -> (a -> m b) -> m b
forall (m :: * -> *) a b. Monad m => m a -> (a -> m b) -> m b
>>= \case
Left r
r -> Stream (Of Text) m r -> m (Stream (Of Text) m r)
forall a. a -> m a
forall (f :: * -> *) a. Applicative f => a -> f a
pure (Text -> Stream (Of Text) m ()
forall {m :: * -> *}. Monad m => Text -> Stream (Of Text) m ()
emit (ByteString -> Text
decodeUtf16LE ByteString
carry) Stream (Of Text) m ()
-> Stream (Of Text) m r -> Stream (Of Text) m r
forall a b.
Stream (Of Text) m a
-> Stream (Of Text) m b -> Stream (Of Text) m b
forall (m :: * -> *) a b. Monad m => m a -> m b -> m b
>> r -> Stream (Of Text) m r
forall a. a -> Stream (Of Text) m a
forall (f :: * -> *) a. Applicative f => a -> f a
pure r
r)
Right (ByteString
bs, Stream (Of ByteString) m r
next) ->
let ([Text]
texts, ByteString
tailBytes) = ByteString -> ByteString -> ([Text], ByteString)
push ByteString
carry ByteString
bs
in Stream (Of Text) m r -> m (Stream (Of Text) m r)
forall a. a -> m a
forall (f :: * -> *) a. Applicative f => a -> f a
pure ((Text -> Stream (Of Text) m ()) -> [Text] -> Stream (Of Text) m ()
forall (t :: * -> *) (m :: * -> *) a b.
(Foldable t, Monad m) =>
(a -> m b) -> t a -> m ()
mapM_ Text -> Stream (Of Text) m ()
forall {m :: * -> *}. Monad m => Text -> Stream (Of Text) m ()
emit [Text]
texts Stream (Of Text) m ()
-> Stream (Of Text) m r -> Stream (Of Text) m r
forall a b.
Stream (Of Text) m a
-> Stream (Of Text) m b -> Stream (Of Text) m b
forall (m :: * -> *) a b. Monad m => m a -> m b -> m b
>> ByteString -> Stream (Of ByteString) m r -> Stream (Of Text) m r
go ByteString
tailBytes Stream (Of ByteString) m r
next)
emit :: Text -> Stream (Of Text) m ()
emit Text
t = if Text -> Bool
T.null Text
t then () -> Stream (Of Text) m ()
forall a. a -> Stream (Of Text) m a
forall (f :: * -> *) a. Applicative f => a -> f a
pure () else Text -> Stream (Of Text) m ()
forall (m :: * -> *) a. Monad m => a -> Stream (Of a) m ()
S.yield Text
t
push :: ByteString -> ByteString -> ([Text], ByteString)
push ByteString
carry ByteString
bs
| ByteString -> Bool
B.null ByteString
carry = ByteString -> ([Text], ByteString)
block ByteString
bs
| ByteString -> Bool
B.null ByteString
bs = ([], ByteString
carry)
| ByteString -> Int
B.length ByteString
prefix Int -> Int -> Bool
forall a. Ord a => a -> a -> Bool
< Int
2 Bool -> Bool -> Bool
|| (Int -> Bool
forall {a}. (Ord a, Num a) => a -> Bool
high Int
first Bool -> Bool -> Bool
&& ByteString -> Int
B.length ByteString
prefix Int -> Int -> Bool
forall a. Ord a => a -> a -> Bool
< Int
4) = ([], ByteString -> ByteString
B.copy ByteString
prefix)
| Bool
otherwise =
let n :: Int
n = if Int -> Bool
forall {a}. (Ord a, Num a) => a -> Bool
high Int
first Bool -> Bool -> Bool
&& Int -> Bool
forall {a}. (Ord a, Num a) => a -> Bool
low (ByteString -> Int -> Int
unit ByteString
prefix Int
2) then Int
4 else Int
2
text :: Text
text = ByteString -> Text
decodeUtf16LE (Int -> ByteString -> ByteString
B.take Int
n ByteString
prefix)
([Text]
later, ByteString
pending) = if Int
n Int -> Int -> Bool
forall a. Ord a => a -> a -> Bool
>= ByteString -> Int
B.length ByteString
carry
then ByteString -> ([Text], ByteString)
block (Int -> ByteString -> ByteString
B.drop (Int
n Int -> Int -> Int
forall a. Num a => a -> a -> a
- ByteString -> Int
B.length ByteString
carry) ByteString
bs)
else ByteString -> ByteString -> ([Text], ByteString)
push (Int -> ByteString -> ByteString
B.drop Int
n ByteString
carry) ByteString
bs
in (Text
text Text -> [Text] -> [Text]
forall a. a -> [a] -> [a]
: [Text]
later, ByteString
pending)
where
prefix :: ByteString
prefix = ByteString
carry ByteString -> ByteString -> ByteString
forall a. Semigroup a => a -> a -> a
<> Int -> ByteString -> ByteString
B.take (Int
4 Int -> Int -> Int
forall a. Num a => a -> a -> a
- ByteString -> Int
B.length ByteString
carry) ByteString
bs
first :: Int
first = ByteString -> Int -> Int
unit ByteString
prefix Int
0
block :: ByteString -> ([Text], ByteString)
block ByteString
bs =
let evenLength :: Int
evenLength = ByteString -> Int
B.length ByteString
bs Int -> Int -> Int
forall a. Num a => a -> a -> a
- ByteString -> Int
B.length ByteString
bs Int -> Int -> Int
forall a. Integral a => a -> a -> a
`mod` Int
2
n :: Int
n = if Int
evenLength Int -> Int -> Bool
forall a. Ord a => a -> a -> Bool
>= Int
2 Bool -> Bool -> Bool
&& Int -> Bool
forall {a}. (Ord a, Num a) => a -> Bool
high (ByteString -> Int -> Int
unit ByteString
bs (Int
evenLength Int -> Int -> Int
forall a. Num a => a -> a -> a
- Int
2)) then Int
evenLength Int -> Int -> Int
forall a. Num a => a -> a -> a
- Int
2 else Int
evenLength
in ([ByteString -> Text
decodeUtf16LE (Int -> ByteString -> ByteString
B.take Int
n ByteString
bs)], ByteString -> ByteString
B.copy (Int -> ByteString -> ByteString
B.drop Int
n ByteString
bs))
unit :: ByteString -> Int -> Int
unit ByteString
bs Int
i = Word8 -> Int
forall a b. (Integral a, Num b) => a -> b
fromIntegral (HasCallStack => ByteString -> Int -> Word8
ByteString -> Int -> Word8
B.index ByteString
bs Int
i) Int -> Int -> Int
forall a. Num a => a -> a -> a
+ Int
256 Int -> Int -> Int
forall a. Num a => a -> a -> a
* Word8 -> Int
forall a b. (Integral a, Num b) => a -> b
fromIntegral (HasCallStack => ByteString -> Int -> Word8
ByteString -> Int -> Word8
B.index ByteString
bs (Int
i Int -> Int -> Int
forall a. Num a => a -> a -> a
+ Int
1)) :: Int
high :: a -> Bool
high a
n = a
n a -> a -> Bool
forall a. Ord a => a -> a -> Bool
>= a
0xD800 Bool -> Bool -> Bool
&& a
n a -> a -> Bool
forall a. Ord a => a -> a -> Bool
<= a
0xDBFF
low :: a -> Bool
low a
n = a
n a -> a -> Bool
forall a. Ord a => a -> a -> Bool
>= a
0xDC00 Bool -> Bool -> Bool
&& a
n a -> a -> Bool
forall a. Ord a => a -> a -> Bool
<= a
0xDFFF
decodeInto :: Ptr Word8 -> Int -> A.MArray RealWorld -> Int -> IO (A.MArray RealWorld, Int, Int)
decodeInto :: Ptr Word8
-> Int
-> MArray RealWorld
-> Int
-> IO (MArray RealWorld, Int, Int)
decodeInto Ptr Word8
p Int
len MArray RealWorld
marr0 Int
cap0 = Int -> Int -> IO (MArray RealWorld, Int, Int)
ascii Int
0 Int
0
where
ascii :: Int -> Int -> IO (MArray RealWorld, Int, Int)
ascii !Int
i !Int
o
| ByteOrder
targetByteOrder ByteOrder -> ByteOrder -> Bool
forall a. Eq a => a -> a -> Bool
== ByteOrder
LittleEndian, Int
i Int -> Int -> Int
forall a. Num a => a -> a -> a
+ Int
16 Int -> Int -> Bool
forall a. Ord a => a -> a -> Bool
<= Int
len = do
w0 <- Int -> IO Word64
word64At Int
i
w1 <- word64At (i + 8)
if asciiUnits (w0 .|. w1)
then writeW64 marr0 o (narrow w0 .|. (narrow w1 `unsafeShiftL` 32)) >> ascii (i + 16) (o + 8)
else asciiUnit i o
| Int
i Int -> Int -> Int
forall a. Num a => a -> a -> a
+ Int
2 Int -> Int -> Bool
forall a. Ord a => a -> a -> Bool
<= Int
len = Int -> Int -> IO (MArray RealWorld, Int, Int)
asciiUnit Int
i Int
o
| Int
i Int -> Int -> Bool
forall a. Ord a => a -> a -> Bool
>= Int
len = (MArray RealWorld, Int, Int) -> IO (MArray RealWorld, Int, Int)
forall a. a -> IO a
forall (f :: * -> *) a. Applicative f => a -> f a
pure (MArray RealWorld
marr0, Int
cap0, Int
o)
| Bool
otherwise = Int -> Int -> IO (MArray RealWorld, Int, Int)
grow Int
i Int
o
asciiUnit :: Int -> Int -> IO (MArray RealWorld, Int, Int)
asciiUnit !Int
i !Int
o = do
u <- Int -> IO Int
unitAt Int
i
if u < 0x80
then writeW8 marr0 o (fromIntegral u) >> ascii (i + 2) (o + 1)
else grow i o
grow :: Int -> Int -> IO (MArray RealWorld, Int, Int)
grow !Int
i !Int
o = do
let cap :: Int
cap = Int -> Int -> Int
maxLength Int
o (Int
len Int -> Int -> Int
forall a. Num a => a -> a -> a
- Int
i)
marr <- if Int
cap Int -> Int -> Bool
forall a. Ord a => a -> a -> Bool
<= Int
cap0 then MArray RealWorld -> IO (MArray RealWorld)
forall a. a -> IO a
forall (f :: * -> *) a. Applicative f => a -> f a
pure MArray RealWorld
marr0 else ST RealWorld (MArray RealWorld) -> IO (MArray RealWorld)
forall a. ST RealWorld a -> IO a
stToIO (MArray RealWorld -> Int -> ST RealWorld (MArray RealWorld)
forall s. MArray s -> Int -> ST s (MArray s)
A.resizeM MArray RealWorld
marr0 Int
cap)
o' <- general marr i o
pure (marr, max cap cap0, o')
general :: A.MArray RealWorld -> Int -> Int -> IO Int
general :: MArray RealWorld -> Int -> Int -> IO Int
general MArray RealWorld
marr = Int -> Int -> IO Int
go
where
go :: Int -> Int -> IO Int
go !Int
i !Int
o
| Int
i Int -> Int -> Int
forall a. Num a => a -> a -> a
+ Int
2 Int -> Int -> Bool
forall a. Ord a => a -> a -> Bool
> Int
len =
if Int
i Int -> Int -> Bool
forall a. Ord a => a -> a -> Bool
< Int
len then Int -> IO ()
replacement Int
o IO () -> IO Int -> IO Int
forall a b. IO a -> IO b -> IO b
forall (m :: * -> *) a b. Monad m => m a -> m b -> m b
>> Int -> IO Int
forall a. a -> IO a
forall (f :: * -> *) a. Applicative f => a -> f a
pure (Int
o Int -> Int -> Int
forall a. Num a => a -> a -> a
+ Int
3) else Int -> IO Int
forall a. a -> IO a
forall (f :: * -> *) a. Applicative f => a -> f a
pure Int
o
| Bool
otherwise = do
u <- Int -> IO Int
unitAt Int
i
if
| u < 0x80 -> writeW8 marr o (fromIntegral u) >> run (i + 2) (o + 1)
| u < 0x800 -> do
writeW8 marr o (fromIntegral (0xC0 .|. (u `unsafeShiftR` 6)))
writeW8 marr (o + 1) (fromIntegral (0x80 .|. (u .&. 0x3F)))
go (i + 2) (o + 2)
| u < 0xD800 || u > 0xDFFF -> three u o >> go (i + 2) (o + 3)
| u <= 0xDBFF, i + 4 <= len -> do
lo <- unitAt (i + 2)
if lo >= 0xDC00 && lo <= 0xDFFF
then do
let c = Int
0x10000 Int -> Int -> Int
forall a. Num a => a -> a -> a
+ ((Int
u Int -> Int -> Int
forall a. Num a => a -> a -> a
- Int
0xD800) Int -> Int -> Int
forall a. Bits a => a -> Int -> a
`unsafeShiftL` Int
10) Int -> Int -> Int
forall a. Num a => a -> a -> a
+ (Int
lo Int -> Int -> Int
forall a. Num a => a -> a -> a
- Int
0xDC00)
writeW8 marr o (fromIntegral (0xF0 .|. (c `unsafeShiftR` 18)))
writeW8 marr (o + 1) (fromIntegral (0x80 .|. ((c `unsafeShiftR` 12) .&. 0x3F)))
writeW8 marr (o + 2) (fromIntegral (0x80 .|. ((c `unsafeShiftR` 6) .&. 0x3F)))
writeW8 marr (o + 3) (fromIntegral (0x80 .|. (c .&. 0x3F)))
go (i + 4) (o + 4)
else replacement o >> go (i + 2) (o + 3)
| otherwise -> replacement o >> go (i + 2) (o + 3)
run :: Int -> Int -> IO Int
run !Int
i !Int
o
| ByteOrder
targetByteOrder ByteOrder -> ByteOrder -> Bool
forall a. Eq a => a -> a -> Bool
== ByteOrder
LittleEndian, Int
i Int -> Int -> Int
forall a. Num a => a -> a -> a
+ Int
16 Int -> Int -> Bool
forall a. Ord a => a -> a -> Bool
<= Int
len = do
w0 <- Int -> IO Word64
word64At Int
i
w1 <- word64At (i + 8)
if asciiUnits (w0 .|. w1)
then writeW64 marr o (narrow w0 .|. (narrow w1 `unsafeShiftL` 32)) >> run (i + 16) (o + 8)
else go i o
| Bool
otherwise = Int -> Int -> IO Int
go Int
i Int
o
three :: Int -> Int -> IO ()
three :: Int -> Int -> IO ()
three Int
c Int
o
| ByteOrder
targetByteOrder ByteOrder -> ByteOrder -> Bool
forall a. Eq a => a -> a -> Bool
== ByteOrder
LittleEndian =
MArray RealWorld -> Int -> Word32 -> IO ()
writeW32 MArray RealWorld
marr Int
o (Word32 -> IO ()) -> Word32 -> IO ()
forall a b. (a -> b) -> a -> b
$ Int -> Word32
forall a b. (Integral a, Num b) => a -> b
fromIntegral (Int -> Word32) -> Int -> Word32
forall a b. (a -> b) -> a -> b
$
(Int
0xE0 Int -> Int -> Int
forall a. Bits a => a -> a -> a
.|. (Int
c Int -> Int -> Int
forall a. Bits a => a -> Int -> a
`unsafeShiftR` Int
12))
Int -> Int -> Int
forall a. Bits a => a -> a -> a
.|. ((Int
0x80 Int -> Int -> Int
forall a. Bits a => a -> a -> a
.|. ((Int
c Int -> Int -> Int
forall a. Bits a => a -> Int -> a
`unsafeShiftR` Int
6) Int -> Int -> Int
forall a. Bits a => a -> a -> a
.&. Int
0x3F)) Int -> Int -> Int
forall a. Bits a => a -> Int -> a
`unsafeShiftL` Int
8)
Int -> Int -> Int
forall a. Bits a => a -> a -> a
.|. ((Int
0x80 Int -> Int -> Int
forall a. Bits a => a -> a -> a
.|. (Int
c Int -> Int -> Int
forall a. Bits a => a -> a -> a
.&. Int
0x3F)) Int -> Int -> Int
forall a. Bits a => a -> Int -> a
`unsafeShiftL` Int
16)
| Bool
otherwise = do
MArray RealWorld -> Int -> Word8 -> IO ()
writeW8 MArray RealWorld
marr Int
o (Int -> Word8
forall a b. (Integral a, Num b) => a -> b
fromIntegral (Int
0xE0 Int -> Int -> Int
forall a. Bits a => a -> a -> a
.|. (Int
c Int -> Int -> Int
forall a. Bits a => a -> Int -> a
`unsafeShiftR` Int
12)))
MArray RealWorld -> Int -> Word8 -> IO ()
writeW8 MArray RealWorld
marr (Int
o Int -> Int -> Int
forall a. Num a => a -> a -> a
+ Int
1) (Int -> Word8
forall a b. (Integral a, Num b) => a -> b
fromIntegral (Int
0x80 Int -> Int -> Int
forall a. Bits a => a -> a -> a
.|. ((Int
c Int -> Int -> Int
forall a. Bits a => a -> Int -> a
`unsafeShiftR` Int
6) Int -> Int -> Int
forall a. Bits a => a -> a -> a
.&. Int
0x3F)))
MArray RealWorld -> Int -> Word8 -> IO ()
writeW8 MArray RealWorld
marr (Int
o Int -> Int -> Int
forall a. Num a => a -> a -> a
+ Int
2) (Int -> Word8
forall a b. (Integral a, Num b) => a -> b
fromIntegral (Int
0x80 Int -> Int -> Int
forall a. Bits a => a -> a -> a
.|. (Int
c Int -> Int -> Int
forall a. Bits a => a -> a -> a
.&. Int
0x3F)))
replacement :: Int -> IO ()
replacement = Int -> Int -> IO ()
three Int
0xFFFD
unitAt :: Int -> IO Int
unitAt :: Int -> IO Int
unitAt Int
i = Word16 -> Int
forall a b. (Integral a, Num b) => a -> b
fromIntegral (Word16 -> Int) -> IO Word16 -> IO Int
forall (f :: * -> *) a b. Functor f => (a -> b) -> f a -> f b
<$> Ptr Word8 -> Int -> IO Word16
peekWord16LE Ptr Word8
p Int
i
{-# INLINE unitAt #-}
word64At :: Int -> IO Word64
word64At :: Int -> IO Word64
word64At Int
i = Ptr Word8 -> Int -> IO Word64
peekWord64LE Ptr Word8
p Int
i
{-# INLINE word64At #-}
asciiUnits :: a -> Bool
asciiUnits a
w = a
w a -> a -> a
forall a. Bits a => a -> a -> a
.&. a
0xFF80FF80FF80FF80 a -> a -> Bool
forall a. Eq a => a -> a -> Bool
== a
0
narrow :: Word64 -> Word64
narrow :: Word64 -> Word64
narrow Word64
x0 =
let x1 :: Word64
x1 = (Word64
x0 Word64 -> Word64 -> Word64
forall a. Bits a => a -> a -> a
.|. (Word64
x0 Word64 -> Int -> Word64
forall a. Bits a => a -> Int -> a
`unsafeShiftR` Int
8)) Word64 -> Word64 -> Word64
forall a. Bits a => a -> a -> a
.&. Word64
0x0000FFFF0000FFFF
in (Word64
x1 Word64 -> Word64 -> Word64
forall a. Bits a => a -> a -> a
.|. (Word64
x1 Word64 -> Int -> Word64
forall a. Bits a => a -> Int -> a
`unsafeShiftR` Int
16)) Word64 -> Word64 -> Word64
forall a. Bits a => a -> a -> a
.&. Word64
0xFFFFFFFF
maxLength :: Int -> Int -> Int
maxLength :: Int -> Int -> Int
maxLength Int
o Int
n = Int
o Int -> Int -> Int
forall a. Num a => a -> a -> a
+ Int
3 Int -> Int -> Int
forall a. Num a => a -> a -> a
* (Int
n Int -> Int -> Int
forall a. Bits a => a -> Int -> a
`unsafeShiftR` Int
1) Int -> Int -> Int
forall a. Num a => a -> a -> a
+ (if Int -> Bool
forall a. Integral a => a -> Bool
odd Int
n then Int
3 else Int
0) Int -> Int -> Int
forall a. Num a => a -> a -> a
+ Int
1
{-# INLINE maxLength #-}
writeW8 :: A.MArray RealWorld -> Int -> Word8 -> IO ()
writeW8 :: MArray RealWorld -> Int -> Word8 -> IO ()
writeW8 MArray RealWorld
marr Int
o Word8
w = ST RealWorld () -> IO ()
forall a. ST RealWorld a -> IO a
stToIO (MArray RealWorld -> Int -> Word8 -> ST RealWorld ()
forall s. MArray s -> Int -> Word8 -> ST s ()
A.unsafeWrite MArray RealWorld
marr Int
o Word8
w)
{-# INLINE writeW8 #-}
writeW32 :: A.MArray RealWorld -> Int -> Word32 -> IO ()
writeW32 :: MArray RealWorld -> Int -> Word32 -> IO ()
writeW32 (MutableByteArray MutableByteArray# RealWorld
mba) (I# Int#
o) (W32# Word32#
w) = (State# RealWorld -> (# State# RealWorld, () #)) -> IO ()
forall a. (State# RealWorld -> (# State# RealWorld, a #)) -> IO a
IO ((State# RealWorld -> (# State# RealWorld, () #)) -> IO ())
-> (State# RealWorld -> (# State# RealWorld, () #)) -> IO ()
forall a b. (a -> b) -> a -> b
$ \State# RealWorld
s -> (# MutableByteArray# RealWorld
-> Int# -> Word32# -> State# RealWorld -> State# RealWorld
forall d.
MutableByteArray# d -> Int# -> Word32# -> State# d -> State# d
writeWord8ArrayAsWord32# MutableByteArray# RealWorld
mba Int#
o Word32#
w State# RealWorld
s, () #)
{-# INLINE writeW32 #-}
writeW64 :: A.MArray RealWorld -> Int -> Word64 -> IO ()
writeW64 :: MArray RealWorld -> Int -> Word64 -> IO ()
writeW64 (MutableByteArray MutableByteArray# RealWorld
mba) (I# Int#
o) (W64# Word64#
w) = (State# RealWorld -> (# State# RealWorld, () #)) -> IO ()
forall a. (State# RealWorld -> (# State# RealWorld, a #)) -> IO a
IO ((State# RealWorld -> (# State# RealWorld, () #)) -> IO ())
-> (State# RealWorld -> (# State# RealWorld, () #)) -> IO ()
forall a b. (a -> b) -> a -> b
$ \State# RealWorld
s -> (# MutableByteArray# RealWorld
-> Int# -> Word64# -> State# RealWorld -> State# RealWorld
forall d.
MutableByteArray# d -> Int# -> Word64# -> State# d -> State# d
writeWord8ArrayAsWord64# MutableByteArray# RealWorld
mba Int#
o Word64#
w State# RealWorld
s, () #)
{-# INLINE writeW64 #-}