    {-# LANGUAGE CPP, MagicHash, BangPatterns #-}

    -- |
    -- Module      : Data.Text.Internal.Encoding.Utf8
    -- Copyright   : (c) 2008, 2009 Tom Harper,
    --               (c) 2009, 2010 Bryan O'Sullivan,
    --               (c) 2009 Duncan Coutts
    --
    -- License     : BSD-style
    -- Maintainer  : bos@serpentine.com
    -- Stability   : experimental
    -- Portability : GHC
    --
    -- /Warning/: this is an internal module, and does not have a stable
    -- API or name. Functions in this module may not check or enforce
    -- preconditions expected by public modules. Use at your own risk!
    --
    -- Basic UTF-8 validation and character manipulation.
    module Data.Text.Internal.Encoding.Utf8
        (
        -- Decomposition
          ord2
        , ord3
        , ord4
        -- Construction
        , chr2
        , chr3
        , chr4
        -- * Validation
        , validate1
        , validate2
        , validate3
        , validate4
        ) where

    import Data.Bits ((.&.))
    import Data.Text.Internal.Unsafe.Char (ord)
    import Data.Text.Internal.Unsafe.Shift (shiftR)
    import GHC.Exts
    import GHC.Word (Word8(..))

    #if !MIN_VERSION_base(4,16,0)
    -- harmless to import, except for warnings that it is unused.
    import Data.Text.Internal.PrimCompat (word8ToWord#)
    #endif

    default(Int)

    between :: Word8                -- ^ byte to check
            -> Word8                -- ^ lower bound
            -> Word8                -- ^ upper bound
            -> Bool
    between :: Word8 -> Word8 -> Word8 -> Bool
    between Word8
    x Word8
    y Word8
    z = Word8
    x Word8 -> Word8 -> Bool
    forall a. Ord a => a -> a -> Bool
    >= Word8
    y Bool -> Bool -> Bool
    && Word8
    x Word8 -> Word8 -> Bool
    forall a. Ord a => a -> a -> Bool
    <= Word8
    z
    {-# INLINE between #-}

    ord2 :: Char -> (Word8,Word8)
    ord2 :: Char -> (Word8, Word8)
    ord2 Char
    c =
        -- ord2 is used only in test suite to construct a deliberately invalid ByteString,
        -- actually violating the assertion, so it is commented out
        -- assert (n >= 0x80 && n <= 0x07ff)
        (Word8
    x1,Word8
    x2)
        where
          n :: Int
    n  = Char -> Int
    ord Char
    c
          x1 :: Word8
    x1 = Int -> Word8
    intToWord8 (Int -> Word8) -> Int -> Word8
    forall a b. (a -> b) -> a -> b
    $ (Int
    n Int -> Int -> Int
    forall a. UnsafeShift a => a -> Int -> a
    `shiftR` Int
    6) Int -> Int -> Int
    forall a. Num a => a -> a -> a
    + Int
    0xC0
          x2 :: Word8
    x2 = Int -> Word8
    intToWord8 (Int -> Word8) -> Int -> Word8
    forall a b. (a -> b) -> a -> b
    $ (Int
    n Int -> Int -> Int
    forall a. Bits a => a -> a -> a
    .&. Int
    0x3F)   Int -> Int -> Int
    forall a. Num a => a -> a -> a
    + Int
    0x80

    ord3 :: Char -> (Word8,Word8,Word8)
    ord3 :: Char -> (Word8, Word8, Word8)
    ord3 Char
    c =
        -- ord3 is used only in test suite to construct a deliberately invalid ByteString,
        -- actually violating the assertion, so it is commented out
        -- assert (n >= 0x0800 && n <= 0xffff)
        (Word8
    x1,Word8
    x2,Word8
    x3)
        where
          n :: Int
    n  = Char -> Int
    ord Char
    c
          x1 :: Word8
    x1 = Int -> Word8
    intToWord8 (Int -> Word8) -> Int -> Word8
    forall a b. (a -> b) -> a -> b
    $ (Int
    n Int -> Int -> Int
    forall a. UnsafeShift a => a -> Int -> a
    `shiftR` Int
    12) Int -> Int -> Int
    forall a. Num a => a -> a -> a
    + Int
    0xE0
          x2 :: Word8
    x2 = Int -> Word8
    intToWord8 (Int -> Word8) -> Int -> Word8
    forall a b. (a -> b) -> a -> b
    $ ((Int
    n Int -> Int -> Int
    forall a. UnsafeShift a => a -> Int -> a
    `shiftR` Int
    6) Int -> Int -> Int
    forall a. Bits a => a -> a -> a
    .&. Int
    0x3F) Int -> Int -> Int
    forall a. Num a => a -> a -> a
    + Int
    0x80
          x3 :: Word8
    x3 = Int -> Word8
    intToWord8 (Int -> Word8) -> Int -> Word8
    forall a b. (a -> b) -> a -> b
    $ (Int
    n Int -> Int -> Int
    forall a. Bits a => a -> a -> a
    .&. Int
    0x3F) Int -> Int -> Int
    forall a. Num a => a -> a -> a
    + Int
    0x80

    ord4 :: Char -> (Word8,Word8,Word8,Word8)
    ord4 :: Char -> (Word8, Word8, Word8, Word8)
    ord4 Char
    c =
        -- ord4 is used only in test suite to construct a deliberately invalid ByteString,
        -- actually violating the assertion, so it is commented out
        -- assert (n >= 0x10000)
        (Word8
    x1,Word8
    x2,Word8
    x3,Word8
    x4)
        where
          n :: Int
    n  = Char -> Int
    ord Char
    c
          x1 :: Word8
    x1 = Int -> Word8
    intToWord8 (Int -> Word8) -> Int -> Word8
    forall a b. (a -> b) -> a -> b
    $ (Int
    n Int -> Int -> Int
    forall a. UnsafeShift a => a -> Int -> a
    `shiftR` Int
    18) Int -> Int -> Int
    forall a. Num a => a -> a -> a
    + Int
    0xF0
          x2 :: Word8
    x2 = Int -> Word8
    intToWord8 (Int -> Word8) -> Int -> Word8
    forall a b. (a -> b) -> a -> b
    $ ((Int
    n Int -> Int -> Int
    forall a. UnsafeShift a => a -> Int -> a
    `shiftR` Int
    12) Int -> Int -> Int
    forall a. Bits a => a -> a -> a
    .&. Int
    0x3F) Int -> Int -> Int
    forall a. Num a => a -> a -> a
    + Int
    0x80
          x3 :: Word8
    x3 = Int -> Word8
    intToWord8 (Int -> Word8) -> Int -> Word8
    forall a b. (a -> b) -> a -> b
    $ ((Int
    n Int -> Int -> Int
    forall a. UnsafeShift a => a -> Int -> a
    `shiftR` Int
    6) Int -> Int -> Int
    forall a. Bits a => a -> a -> a
    .&. Int
    0x3F) Int -> Int -> Int
    forall a. Num a => a -> a -> a
    + Int
    0x80
          x4 :: Word8
    x4 = Int -> Word8
    intToWord8 (Int -> Word8) -> Int -> Word8
    forall a b. (a -> b) -> a -> b
    $ (Int
    n Int -> Int -> Int
    forall a. Bits a => a -> a -> a
    .&. Int
    0x3F) Int -> Int -> Int
    forall a. Num a => a -> a -> a
    + Int
    0x80

    chr2 :: Word8 -> Word8 -> Char
    chr2 :: Word8 -> Word8 -> Char
    chr2 (W8# Word8#
    x1#) (W8# Word8#
    x2#) = Char# -> Char
    C# (Int# -> Char#
    chr# (Int#
    z1# Int# -> Int# -> Int#
    +# Int#
    z2#))
        where
          !y1# :: Int#
    y1# = Word# -> Int#
    word2Int# (Word8# -> Word#
    word8ToWord# Word8#
    x1#)
          !y2# :: Int#
    y2# = Word# -> Int#
    word2Int# (Word8# -> Word#
    word8ToWord# Word8#
    x2#)
          !z1# :: Int#
    z1# = Int# -> Int# -> Int#
    uncheckedIShiftL# (Int#
    y1# Int# -> Int# -> Int#
    -# Int#
    0xC0#) Int#
    6#
          !z2# :: Int#
    z2# = Int#
    y2# Int# -> Int# -> Int#
    -# Int#
    0x80#
    {-# INLINE chr2 #-}

    chr3 :: Word8 -> Word8 -> Word8 -> Char
    chr3 :: Word8 -> Word8 -> Word8 -> Char
    chr3 (W8# Word8#
    x1#) (W8# Word8#
    x2#) (W8# Word8#
    x3#) = Char# -> Char
    C# (Int# -> Char#
    chr# (Int#
    z1# Int# -> Int# -> Int#
    +# Int#
    z2# Int# -> Int# -> Int#
    +# Int#
    z3#))
        where
          !y1# :: Int#
    y1# = Word# -> Int#
    word2Int# (Word8# -> Word#
    word8ToWord# Word8#
    x1#)
          !y2# :: Int#
    y2# = Word# -> Int#
    word2Int# (Word8# -> Word#
    word8ToWord# Word8#
    x2#)
          !y3# :: Int#
    y3# = Word# -> Int#
    word2Int# (Word8# -> Word#
    word8ToWord# Word8#
    x3#)
          !z1# :: Int#
    z1# = Int# -> Int# -> Int#
    uncheckedIShiftL# (Int#
    y1# Int# -> Int# -> Int#
    -# Int#
    0xE0#) Int#
    12#
          !z2# :: Int#
    z2# = Int# -> Int# -> Int#
    uncheckedIShiftL# (Int#
    y2# Int# -> Int# -> Int#
    -# Int#
    0x80#) Int#
    6#
          !z3# :: Int#
    z3# = Int#
    y3# Int# -> Int# -> Int#
    -# Int#
    0x80#
    {-# INLINE chr3 #-}

    chr4             :: Word8 -> Word8 -> Word8 -> Word8 -> Char
    chr4 :: Word8 -> Word8 -> Word8 -> Word8 -> Char
    chr4 (W8# Word8#
    x1#) (W8# Word8#
    x2#) (W8# Word8#
    x3#) (W8# Word8#
    x4#) =
        Char# -> Char
    C# (Int# -> Char#
    chr# (Int#
    z1# Int# -> Int# -> Int#
    +# Int#
    z2# Int# -> Int# -> Int#
    +# Int#
    z3# Int# -> Int# -> Int#
    +# Int#
    z4#))
        where
          !y1# :: Int#
    y1# = Word# -> Int#
    word2Int# (Word8# -> Word#
    word8ToWord# Word8#
    x1#)
          !y2# :: Int#
    y2# = Word# -> Int#
    word2Int# (Word8# -> Word#
    word8ToWord# Word8#
    x2#)
          !y3# :: Int#
    y3# = Word# -> Int#
    word2Int# (Word8# -> Word#
    word8ToWord# Word8#
    x3#)
          !y4# :: Int#
    y4# = Word# -> Int#
    word2Int# (Word8# -> Word#
    word8ToWord# Word8#
    x4#)
          !z1# :: Int#
    z1# = Int# -> Int# -> Int#
    uncheckedIShiftL# (Int#
    y1# Int# -> Int# -> Int#
    -# Int#
    0xF0#) Int#
    18#
          !z2# :: Int#
    z2# = Int# -> Int# -> Int#
    uncheckedIShiftL# (Int#
    y2# Int# -> Int# -> Int#
    -# Int#
    0x80#) Int#
    12#
          !z3# :: Int#
    z3# = Int# -> Int# -> Int#
    uncheckedIShiftL# (Int#
    y3# Int# -> Int# -> Int#
    -# Int#
    0x80#) Int#
    6#
          !z4# :: Int#
    z4# = Int#
    y4# Int# -> Int# -> Int#
    -# Int#
    0x80#
    {-# INLINE chr4 #-}

    validate1 :: Word8 -> Bool
    validate1 :: Word8 -> Bool
    validate1 Word8
    x1 = Word8
    x1 Word8 -> Word8 -> Bool
    forall a. Ord a => a -> a -> Bool
    <= Word8
    0x7F
    {-# INLINE validate1 #-}

    validate2 :: Word8 -> Word8 -> Bool
    validate2 :: Word8 -> Word8 -> Bool
    validate2 Word8
    x1 Word8
    x2 = Word8 -> Word8 -> Word8 -> Bool
    between Word8
    x1 Word8
    0xC2 Word8
    0xDF Bool -> Bool -> Bool
    && Word8 -> Word8 -> Word8 -> Bool
    between Word8
    x2 Word8
    0x80 Word8
    0xBF
    {-# INLINE validate2 #-}

    validate3 :: Word8 -> Word8 -> Word8 -> Bool
    {-# INLINE validate3 #-}
    validate3 :: Word8 -> Word8 -> Word8 -> Bool
    validate3 Word8
    x1 Word8
    x2 Word8
    x3 = Bool
    validate3_1 Bool -> Bool -> Bool
    || Bool
    validate3_2 Bool -> Bool -> Bool
    || Bool
    validate3_3 Bool -> Bool -> Bool
    || Bool
    validate3_4
      where
        validate3_1 :: Bool
    validate3_1 = (Word8
    x1 Word8 -> Word8 -> Bool
    forall a. Eq a => a -> a -> Bool
    == Word8
    0xE0) Bool -> Bool -> Bool
    &&
                      Word8 -> Word8 -> Word8 -> Bool
    between Word8
    x2 Word8
    0xA0 Word8
    0xBF Bool -> Bool -> Bool
    &&
                      Word8 -> Word8 -> Word8 -> Bool
    between Word8
    x3 Word8
    0x80 Word8
    0xBF
        validate3_2 :: Bool
    validate3_2 = Word8 -> Word8 -> Word8 -> Bool
    between Word8
    x1 Word8
    0xE1 Word8
    0xEC Bool -> Bool -> Bool
    &&
                      Word8 -> Word8 -> Word8 -> Bool
    between Word8
    x2 Word8
    0x80 Word8
    0xBF Bool -> Bool -> Bool
    &&
                      Word8 -> Word8 -> Word8 -> Bool
    between Word8
    x3 Word8
    0x80 Word8
    0xBF
        validate3_3 :: Bool
    validate3_3 = Word8
    x1 Word8 -> Word8 -> Bool
    forall a. Eq a => a -> a -> Bool
    == Word8
    0xED Bool -> Bool -> Bool
    &&
                      Word8 -> Word8 -> Word8 -> Bool
    between Word8
    x2 Word8
    0x80 Word8
    0x9F Bool -> Bool -> Bool
    &&
                      Word8 -> Word8 -> Word8 -> Bool
    between Word8
    x3 Word8
    0x80 Word8
    0xBF
        validate3_4 :: Bool
    validate3_4 = Word8 -> Word8 -> Word8 -> Bool
    between Word8
    x1 Word8
    0xEE Word8
    0xEF Bool -> Bool -> Bool
    &&
                      Word8 -> Word8 -> Word8 -> Bool
    between Word8
    x2 Word8
    0x80 Word8
    0xBF Bool -> Bool -> Bool
    &&
                      Word8 -> Word8 -> Word8 -> Bool
    between Word8
    x3 Word8
    0x80 Word8
    0xBF

    validate4 :: Word8 -> Word8 -> Word8 -> Word8 -> Bool
    {-# INLINE validate4 #-}
    validate4 :: Word8 -> Word8 -> Word8 -> Word8 -> Bool
    validate4 Word8
    x1 Word8
    x2 Word8
    x3 Word8
    x4 = Bool
    validate4_1 Bool -> Bool -> Bool
    || Bool
    validate4_2 Bool -> Bool -> Bool
    || Bool
    validate4_3
      where
        validate4_1 :: Bool
    validate4_1 = Word8
    x1 Word8 -> Word8 -> Bool
    forall a. Eq a => a -> a -> Bool
    == Word8
    0xF0 Bool -> Bool -> Bool
    &&
                      Word8 -> Word8 -> Word8 -> Bool
    between Word8
    x2 Word8
    0x90 Word8
    0xBF Bool -> Bool -> Bool
    &&
                      Word8 -> Word8 -> Word8 -> Bool
    between Word8
    x3 Word8
    0x80 Word8
    0xBF Bool -> Bool -> Bool
    &&
                      Word8 -> Word8 -> Word8 -> Bool
    between Word8
    x4 Word8
    0x80 Word8
    0xBF
        validate4_2 :: Bool
    validate4_2 = Word8 -> Word8 -> Word8 -> Bool
    between Word8
    x1 Word8
    0xF1 Word8
    0xF3 Bool -> Bool -> Bool
    &&
                      Word8 -> Word8 -> Word8 -> Bool
    between Word8
    x2 Word8
    0x80 Word8
    0xBF Bool -> Bool -> Bool
    &&
                      Word8 -> Word8 -> Word8 -> Bool
    between Word8
    x3 Word8
    0x80 Word8
    0xBF Bool -> Bool -> Bool
    &&
                      Word8 -> Word8 -> Word8 -> Bool
    between Word8
    x4 Word8
    0x80 Word8
    0xBF
        validate4_3 :: Bool
    validate4_3 = Word8
    x1 Word8 -> Word8 -> Bool
    forall a. Eq a => a -> a -> Bool
    == Word8
    0xF4 Bool -> Bool -> Bool
    &&
                      Word8 -> Word8 -> Word8 -> Bool
    between Word8
    x2 Word8
    0x80 Word8
    0x8F Bool -> Bool -> Bool
    &&
                      Word8 -> Word8 -> Word8 -> Bool
    between Word8
    x3 Word8
    0x80 Word8
    0xBF Bool -> Bool -> Bool
    &&
                      Word8 -> Word8 -> Word8 -> Bool
    between Word8
    x4 Word8
    0x80 Word8
    0xBF

    intToWord8 :: Int -> Word8
    intToWord8 :: Int -> Word8
    intToWord8 = Int -> Word8
    forall a b. (Integral a, Num b) => a -> b
    fromIntegral