    {-# LANGUAGE CPP, MagicHash #-}

    -- |
    -- Module      : Data.Text.Internal.Unsafe.Char
    -- 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!
    --
    -- Fast character manipulation functions.
    module Data.Text.Internal.Unsafe.Char
        (
          ord
        , unsafeChr
        , unsafeChr8
        , unsafeChr32
        , unsafeWrite
        ) where

    import Control.Monad.ST (ST)
    import Data.Bits ((.&.))
    import Data.Text.Internal.Unsafe.Shift (shiftR)
    import GHC.Exts (Char(..), Int(..), chr#, ord#, word2Int#)
    import GHC.Word (Word8(..), Word16(..), Word32(..))
    import qualified Data.Text.Array as A
    import Data.Text.Internal.PrimCompat ( word8ToWord#, word16ToWord#, word32ToWord# )
    #if defined(ASSERTS)
    import GHC.Stack (HasCallStack)
    #endif

    ord :: Char -> Int
    ord :: Char -> Int
    ord (C# Char#
    c#) = Int# -> Int
    I# (Char# -> Int#
    ord# Char#
    c#)
    {-# INLINE ord #-}

    unsafeChr :: Word16 -> Char
    unsafeChr :: Word16 -> Char
    unsafeChr (W16# Word16#
    w#) = Char# -> Char
    C# (Int# -> Char#
    chr# (Word# -> Int#
    word2Int# (Word16# -> Word#
    word16ToWord# Word16#
    w#)))
    {-# INLINE unsafeChr #-}

    unsafeChr8 :: Word8 -> Char
    unsafeChr8 :: Word8 -> Char
    unsafeChr8 (W8# Word8#
    w#) = Char# -> Char
    C# (Int# -> Char#
    chr# (Word# -> Int#
    word2Int# (Word8# -> Word#
    word8ToWord# Word8#
    w#)))
    {-# INLINE unsafeChr8 #-}

    unsafeChr32 :: Word32 -> Char
    unsafeChr32 :: Word32 -> Char
    unsafeChr32 (W32# Word32#
    w#) = Char# -> Char
    C# (Int# -> Char#
    chr# (Word# -> Int#
    word2Int# (Word32# -> Word#
    word32ToWord# Word32#
    w#)))
    {-# INLINE unsafeChr32 #-}

    -- | Write a character into the array at the given offset.  Returns
    -- the number of 'Word16's written.
    unsafeWrite ::
    #if defined(ASSERTS)
        HasCallStack =>
    #endif
        A.MArray s -> Int -> Char -> ST s Int
    unsafeWrite :: forall s. MArray s -> Int -> Char -> ST s Int
    unsafeWrite MArray s
    marr Int
    i Char
    c
        | Int
    n forall a. Ord a => a -> a -> Bool
    < Int
    0x10000 = do
            forall s. MArray s -> Int -> Word16 -> ST s ()
    A.unsafeWrite MArray s
    marr Int
    i (Int -> Word16
    intToWord16 Int
    n)
            forall (m :: * -> *) a. Monad m => a -> m a
    return Int
    1
        | Bool
    otherwise = do
            forall s. MArray s -> Int -> Word16 -> ST s ()
    A.unsafeWrite MArray s
    marr Int
    i Word16
    lo
            forall s. MArray s -> Int -> Word16 -> ST s ()
    A.unsafeWrite MArray s
    marr (Int
    iforall a. Num a => a -> a -> a
    +Int
    1) Word16
    hi
            forall (m :: * -> *) a. Monad m => a -> m a
    return Int
    2
        where n :: Int
    n = Char -> Int
    ord Char
    c
              m :: Int
    m = Int
    n forall a. Num a => a -> a -> a
    - Int
    0x10000
              lo :: Word16
    lo = Int -> Word16
    intToWord16 forall a b. (a -> b) -> a -> b
    $ (Int
    m forall a. UnsafeShift a => a -> Int -> a
    `shiftR` Int
    10) forall a. Num a => a -> a -> a
    + Int
    0xD800
              hi :: Word16
    hi = Int -> Word16
    intToWord16 forall a b. (a -> b) -> a -> b
    $ (Int
    m forall a. Bits a => a -> a -> a
    .&. Int
    0x3FF) forall a. Num a => a -> a -> a
    + Int
    0xDC00
    {-# INLINE unsafeWrite #-}

    intToWord16 :: Int -> Word16
    intToWord16 :: Int -> Word16
    intToWord16 = forall a b. (Integral a, Num b) => a -> b
    fromIntegral