    {-# OPTIONS_HADDOCK not-home #-}

    -- | Copyright : (c) 2010 - 2011 Simon Meier
    -- License     : BSD3-style (see LICENSE)
    --
    -- Maintainer  : Simon Meier <iridcode@gmail.com>
    -- Portability : GHC
    --
    -- Constructing 'Builder's using ASCII-based encodings.
    --
    module Data.ByteString.Builder.ASCII
        (
          -- ** Formatting numbers as text
          -- | Formatting of numbers as ASCII text.
          --
          -- Note that you can also use these functions for the ISO/IEC 8859-1 and
          -- UTF-8 encodings, as the ASCII encoding is equivalent on the
          -- codepoints 0-127.

          -- *** Decimal numbers
          -- | Decimal encoding of numbers using ASCII encoded characters.
          int8Dec
        , int16Dec
        , int32Dec
        , int64Dec
        , intDec
        , integerDec

        , word8Dec
        , word16Dec
        , word32Dec
        , word64Dec
        , wordDec

        , floatDec
        , doubleDec

          -- *** Hexadecimal numbers

          -- | Encoding positive integers as hexadecimal numbers using lower-case
          -- ASCII characters. The shortest
          -- possible representation is used. For example,
          --
          -- >>> toLazyByteString (word16Hex 0x0a10)
          -- Chunk "a10" Empty
          --
          -- Note that there is no support for using upper-case characters. Please
          -- contact the maintainer, if your application cannot work without
          -- hexadecimal encodings that use upper-case characters.
          --
        , word8Hex
        , word16Hex
        , word32Hex
        , word64Hex
        , wordHex

          -- *** Fixed-width hexadecimal numbers
          --
        , int8HexFixed
        , int16HexFixed
        , int32HexFixed
        , int64HexFixed
        , word8HexFixed
        , word16HexFixed
        , word32HexFixed
        , word64HexFixed

        , floatHexFixed
        , doubleHexFixed

        , byteStringHex
        , lazyByteStringHex

        ) where

    import           Data.ByteString                                as S
    import           Data.ByteString.Lazy                           as L
    import           Data.ByteString.Builder.Internal (Builder)
    import qualified Data.ByteString.Builder.Prim                   as P
    import qualified Data.ByteString.Builder.Prim.Internal          as P
    import           Data.ByteString.Builder.RealFloat (floatDec, doubleDec)
    import           Data.ByteString.Internal.Type (c_int_dec_padded9, c_long_long_int_dec_padded18)

    import           Foreign
    import           Data.List.NonEmpty (NonEmpty(..))

    ------------------------------------------------------------------------------
    -- Decimal Encoding
    ------------------------------------------------------------------------------

    -- Signed integers
    ------------------

    -- | Decimal encoding of an 'Int8' using the ASCII digits.
    --
    -- e.g.
    --
    -- > toLazyByteString (int8Dec 42)   = "42"
    -- > toLazyByteString (int8Dec (-1)) = "-1"
    --
    {-# INLINE int8Dec #-}
    int8Dec :: Int8 -> Builder
    int8Dec :: Int8 -> Builder
    int8Dec = BoundedPrim Int8 -> Int8 -> Builder
    forall a. BoundedPrim a -> a -> Builder
    P.primBounded BoundedPrim Int8
    P.int8Dec

    -- | Decimal encoding of an 'Int16' using the ASCII digits.
    {-# INLINE int16Dec #-}
    int16Dec :: Int16 -> Builder
    int16Dec :: Int16 -> Builder
    int16Dec = BoundedPrim Int16 -> Int16 -> Builder
    forall a. BoundedPrim a -> a -> Builder
    P.primBounded BoundedPrim Int16
    P.int16Dec

    -- | Decimal encoding of an 'Int32' using the ASCII digits.
    {-# INLINE int32Dec #-}
    int32Dec :: Int32 -> Builder
    int32Dec :: Int32 -> Builder
    int32Dec = BoundedPrim Int32 -> Int32 -> Builder
    forall a. BoundedPrim a -> a -> Builder
    P.primBounded BoundedPrim Int32
    P.int32Dec

    -- | Decimal encoding of an 'Int64' using the ASCII digits.
    {-# INLINE int64Dec #-}
    int64Dec :: Int64 -> Builder
    int64Dec :: Int64 -> Builder
    int64Dec = BoundedPrim Int64 -> Int64 -> Builder
    forall a. BoundedPrim a -> a -> Builder
    P.primBounded BoundedPrim Int64
    P.int64Dec

    -- | Decimal encoding of an 'Int' using the ASCII digits.
    {-# INLINE intDec #-}
    intDec :: Int -> Builder
    intDec :: Int -> Builder
    intDec = BoundedPrim Int -> Int -> Builder
    forall a. BoundedPrim a -> a -> Builder
    P.primBounded BoundedPrim Int
    P.intDec

    -- Unsigned integers
    --------------------

    -- | Decimal encoding of a 'Word8' using the ASCII digits.
    {-# INLINE word8Dec #-}
    word8Dec :: Word8 -> Builder
    word8Dec :: Word8 -> Builder
    word8Dec = BoundedPrim Word8 -> Word8 -> Builder
    forall a. BoundedPrim a -> a -> Builder
    P.primBounded BoundedPrim Word8
    P.word8Dec

    -- | Decimal encoding of a 'Word16' using the ASCII digits.
    {-# INLINE word16Dec #-}
    word16Dec :: Word16 -> Builder
    word16Dec :: Word16 -> Builder
    word16Dec = BoundedPrim Word16 -> Word16 -> Builder
    forall a. BoundedPrim a -> a -> Builder
    P.primBounded BoundedPrim Word16
    P.word16Dec

    -- | Decimal encoding of a 'Word32' using the ASCII digits.
    {-# INLINE word32Dec #-}
    word32Dec :: Word32 -> Builder
    word32Dec :: Word32 -> Builder
    word32Dec = BoundedPrim Word32 -> Word32 -> Builder
    forall a. BoundedPrim a -> a -> Builder
    P.primBounded BoundedPrim Word32
    P.word32Dec

    -- | Decimal encoding of a 'Word64' using the ASCII digits.
    {-# INLINE word64Dec #-}
    word64Dec :: Word64 -> Builder
    word64Dec :: Word64 -> Builder
    word64Dec = BoundedPrim Word64 -> Word64 -> Builder
    forall a. BoundedPrim a -> a -> Builder
    P.primBounded BoundedPrim Word64
    P.word64Dec

    -- | Decimal encoding of a 'Word' using the ASCII digits.
    {-# INLINE wordDec #-}
    wordDec :: Word -> Builder
    wordDec :: Word -> Builder
    wordDec = BoundedPrim Word -> Word -> Builder
    forall a. BoundedPrim a -> a -> Builder
    P.primBounded BoundedPrim Word
    P.wordDec

    ------------------------------------------------------------------------------
    -- Hexadecimal Encoding
    ------------------------------------------------------------------------------

    -- without lead
    ---------------

    -- | Shortest hexadecimal encoding of a 'Word8' using lower-case characters.
    {-# INLINE word8Hex #-}
    word8Hex :: Word8 -> Builder
    word8Hex :: Word8 -> Builder
    word8Hex = BoundedPrim Word8 -> Word8 -> Builder
    forall a. BoundedPrim a -> a -> Builder
    P.primBounded BoundedPrim Word8
    P.word8Hex

    -- | Shortest hexadecimal encoding of a 'Word16' using lower-case characters.
    {-# INLINE word16Hex #-}
    word16Hex :: Word16 -> Builder
    word16Hex :: Word16 -> Builder
    word16Hex = BoundedPrim Word16 -> Word16 -> Builder
    forall a. BoundedPrim a -> a -> Builder
    P.primBounded BoundedPrim Word16
    P.word16Hex

    -- | Shortest hexadecimal encoding of a 'Word32' using lower-case characters.
    {-# INLINE word32Hex #-}
    word32Hex :: Word32 -> Builder
    word32Hex :: Word32 -> Builder
    word32Hex = BoundedPrim Word32 -> Word32 -> Builder
    forall a. BoundedPrim a -> a -> Builder
    P.primBounded BoundedPrim Word32
    P.word32Hex

    -- | Shortest hexadecimal encoding of a 'Word64' using lower-case characters.
    {-# INLINE word64Hex #-}
    word64Hex :: Word64 -> Builder
    word64Hex :: Word64 -> Builder
    word64Hex = BoundedPrim Word64 -> Word64 -> Builder
    forall a. BoundedPrim a -> a -> Builder
    P.primBounded BoundedPrim Word64
    P.word64Hex

    -- | Shortest hexadecimal encoding of a 'Word' using lower-case characters.
    {-# INLINE wordHex #-}
    wordHex :: Word -> Builder
    wordHex :: Word -> Builder
    wordHex = BoundedPrim Word -> Word -> Builder
    forall a. BoundedPrim a -> a -> Builder
    P.primBounded BoundedPrim Word
    P.wordHex

    -- fixed width; leading zeroes
    ------------------------------

    -- | Encode a 'Int8' using 2 nibbles (hexadecimal digits).
    {-# INLINE int8HexFixed #-}
    int8HexFixed :: Int8 -> Builder
    int8HexFixed :: Int8 -> Builder
    int8HexFixed = FixedPrim Int8 -> Int8 -> Builder
    forall a. FixedPrim a -> a -> Builder
    P.primFixed FixedPrim Int8
    P.int8HexFixed

    -- | Encode a 'Int16' using 4 nibbles.
    {-# INLINE int16HexFixed #-}
    int16HexFixed :: Int16 -> Builder
    int16HexFixed :: Int16 -> Builder
    int16HexFixed = FixedPrim Int16 -> Int16 -> Builder
    forall a. FixedPrim a -> a -> Builder
    P.primFixed FixedPrim Int16
    P.int16HexFixed

    -- | Encode a 'Int32' using 8 nibbles.
    {-# INLINE int32HexFixed #-}
    int32HexFixed :: Int32 -> Builder
    int32HexFixed :: Int32 -> Builder
    int32HexFixed = FixedPrim Int32 -> Int32 -> Builder
    forall a. FixedPrim a -> a -> Builder
    P.primFixed FixedPrim Int32
    P.int32HexFixed

    -- | Encode a 'Int64' using 16 nibbles.
    {-# INLINE int64HexFixed #-}
    int64HexFixed :: Int64 -> Builder
    int64HexFixed :: Int64 -> Builder
    int64HexFixed = FixedPrim Int64 -> Int64 -> Builder
    forall a. FixedPrim a -> a -> Builder
    P.primFixed FixedPrim Int64
    P.int64HexFixed

    -- | Encode a 'Word8' using 2 nibbles (hexadecimal digits).
    {-# INLINE word8HexFixed #-}
    word8HexFixed :: Word8 -> Builder
    word8HexFixed :: Word8 -> Builder
    word8HexFixed = FixedPrim Word8 -> Word8 -> Builder
    forall a. FixedPrim a -> a -> Builder
    P.primFixed FixedPrim Word8
    P.word8HexFixed

    -- | Encode a 'Word16' using 4 nibbles.
    {-# INLINE word16HexFixed #-}
    word16HexFixed :: Word16 -> Builder
    word16HexFixed :: Word16 -> Builder
    word16HexFixed = FixedPrim Word16 -> Word16 -> Builder
    forall a. FixedPrim a -> a -> Builder
    P.primFixed FixedPrim Word16
    P.word16HexFixed

    -- | Encode a 'Word32' using 8 nibbles.
    {-# INLINE word32HexFixed #-}
    word32HexFixed :: Word32 -> Builder
    word32HexFixed :: Word32 -> Builder
    word32HexFixed = FixedPrim Word32 -> Word32 -> Builder
    forall a. FixedPrim a -> a -> Builder
    P.primFixed FixedPrim Word32
    P.word32HexFixed

    -- | Encode a 'Word64' using 16 nibbles.
    {-# INLINE word64HexFixed #-}
    word64HexFixed :: Word64 -> Builder
    word64HexFixed :: Word64 -> Builder
    word64HexFixed = FixedPrim Word64 -> Word64 -> Builder
    forall a. FixedPrim a -> a -> Builder
    P.primFixed FixedPrim Word64
    P.word64HexFixed

    -- | Encode an IEEE 'Float' using 8 nibbles.
    {-# INLINE floatHexFixed #-}
    floatHexFixed :: Float -> Builder
    floatHexFixed :: Float -> Builder
    floatHexFixed = FixedPrim Float -> Float -> Builder
    forall a. FixedPrim a -> a -> Builder
    P.primFixed FixedPrim Float
    P.floatHexFixed

    -- | Encode an IEEE 'Double' using 16 nibbles.
    {-# INLINE doubleHexFixed #-}
    doubleHexFixed :: Double -> Builder
    doubleHexFixed :: Double -> Builder
    doubleHexFixed = FixedPrim Double -> Double -> Builder
    forall a. FixedPrim a -> a -> Builder
    P.primFixed FixedPrim Double
    P.doubleHexFixed

    -- | Encode each byte of a 'S.StrictByteString' using its fixed-width hex encoding.
    {-# NOINLINE byteStringHex #-} -- share code
    byteStringHex :: S.StrictByteString -> Builder
    byteStringHex :: StrictByteString -> Builder
    byteStringHex = FixedPrim Word8 -> StrictByteString -> Builder
    P.primMapByteStringFixed FixedPrim Word8
    P.word8HexFixed

    -- | Encode each byte of a 'L.LazyByteString' using its fixed-width hex encoding.
    {-# NOINLINE lazyByteStringHex #-} -- share code
    lazyByteStringHex :: L.LazyByteString -> Builder
    lazyByteStringHex :: LazyByteString -> Builder
    lazyByteStringHex = FixedPrim Word8 -> LazyByteString -> Builder
    P.primMapLazyByteStringFixed FixedPrim Word8
    P.word8HexFixed

    ------------------------------------------------------------------------------
    -- Fast decimal 'Integer' encoding.
    ------------------------------------------------------------------------------

    -- An optimized version of the integer serialization code
    -- in blaze-textual (c) 2011 MailRank, Inc. Bryan O'Sullivan
    -- <bos@mailrank.com>. It is 2.5x faster on Int-sized integers and 4.5x faster
    -- on larger integers.

    -- | Maximal power of 10 fitting into an 'Int' without using the MSB.
    --     10 ^ 9  for 32 bit ints  (31 * log 2 / log 10 =  9.33)
    --     10 ^ 18 for 64 bit ints  (63 * log 2 / log 10 = 18.96)
    --
    -- FIXME: Think about also using the MSB. For 64 bit 'Int's this makes a
    -- difference.
    maxPow10 :: Integer
    maxPow10 :: Integer
    maxPow10 = Int -> Integer
    forall a. Integral a => a -> Integer
    toInteger (Int -> Integer) -> Int -> Integer
    forall a b. (a -> b) -> a -> b
    $ (Int
    10 :: Int) Int -> Int -> Int
    forall a b. (Num a, Integral b) => a -> b -> a
    ^ Int -> Int -> Int
    forall a. a -> a -> a
    P.caseWordSize_32_64 (Int
    9 :: Int) Int
    18

    -- | Decimal encoding of an 'Integer' using the ASCII digits.
    integerDec :: Integer -> Builder
    integerDec :: Integer -> Builder
    integerDec Integer
    i
        | Int
    i' <- Integer -> Int
    forall a. Num a => Integer -> a
    fromInteger Integer
    i, Int -> Integer
    forall a. Integral a => a -> Integer
    toInteger Int
    i' Integer -> Integer -> Bool
    forall a. Eq a => a -> a -> Bool
    == Integer
    i = Int -> Builder
    intDec Int
    i'
        | Integer
    i Integer -> Integer -> Bool
    forall a. Ord a => a -> a -> Bool
    < Integer
    0     = FixedPrim Char -> Char -> Builder
    forall a. FixedPrim a -> a -> Builder
    P.primFixed FixedPrim Char
    P.char8 Char
    '-' Builder -> Builder -> Builder
    forall a. Monoid a => a -> a -> a
    `mappend` Integer -> Builder
    go (-Integer
    i)
        | Bool
    otherwise =                                   Integer -> Builder
    go Integer
    i
      where
        go :: Integer -> Builder
        go :: Integer -> Builder
    go Integer
    n | Integer
    n Integer -> Integer -> Bool
    forall a. Ord a => a -> a -> Bool
    < Integer
    maxPow10 = Int -> Builder
    intDec (Integer -> Int
    forall a. Num a => Integer -> a
    fromInteger Integer
    n)
             | Bool
    otherwise    =
                 case NonEmpty Integer -> NonEmpty Int
    putH (Integer -> Integer -> NonEmpty Integer
    splitf (Integer
    maxPow10 Integer -> Integer -> Integer
    forall a. Num a => a -> a -> a
    * Integer
    maxPow10) Integer
    n) of
                   Int
    x:|[Int]
    xs -> Int -> Builder
    intDec Int
    x Builder -> Builder -> Builder
    forall a. Monoid a => a -> a -> a
    `mappend` BoundedPrim Int -> [Int] -> Builder
    forall a. BoundedPrim a -> [a] -> Builder
    P.primMapListBounded BoundedPrim Int
    intDecPadded [Int]
    xs

        splitf :: Integer -> Integer -> NonEmpty Integer
        splitf :: Integer -> Integer -> NonEmpty Integer
    splitf Integer
    pow10 Integer
    n0
          | Integer
    pow10 Integer -> Integer -> Bool
    forall a. Ord a => a -> a -> Bool
    > Integer
    n0  = Integer
    n0 Integer -> [Integer] -> NonEmpty Integer
    forall a. a -> [a] -> NonEmpty a
    :| []
          | Bool
    otherwise   = NonEmpty Integer -> NonEmpty Integer
    splith (Integer -> Integer -> NonEmpty Integer
    splitf (Integer
    pow10 Integer -> Integer -> Integer
    forall a. Num a => a -> a -> a
    * Integer
    pow10) Integer
    n0)
          where
            splith :: NonEmpty Integer -> NonEmpty Integer
    splith (Integer
    n:|[Integer]
    ns) =
                case Integer
    n Integer -> Integer -> (Integer, Integer)
    forall a. Integral a => a -> a -> (a, a)
    `quotRem` Integer
    pow10 of
                    (Integer
    q,Integer
    r) | Integer
    q Integer -> Integer -> Bool
    forall a. Ord a => a -> a -> Bool
    > Integer
    0     -> Integer
    q Integer -> [Integer] -> NonEmpty Integer
    forall a. a -> [a] -> NonEmpty a
    :| Integer
    r Integer -> [Integer] -> [Integer]
    forall a. a -> [a] -> [a]
    :  [Integer] -> [Integer]
    splitb [Integer]
    ns
                          | Bool
    otherwise ->      Integer
    r Integer -> [Integer] -> NonEmpty Integer
    forall a. a -> [a] -> NonEmpty a
    :| [Integer] -> [Integer]
    splitb [Integer]
    ns

            splitb :: [Integer] -> [Integer]
    splitb []     = []
            splitb (Integer
    n:[Integer]
    ns) = case Integer
    n Integer -> Integer -> (Integer, Integer)
    forall a. Integral a => a -> a -> (a, a)
    `quotRem` Integer
    pow10 of
                                (Integer
    q,Integer
    r) -> Integer
    q Integer -> [Integer] -> [Integer]
    forall a. a -> [a] -> [a]
    : Integer
    r Integer -> [Integer] -> [Integer]
    forall a. a -> [a] -> [a]
    : [Integer] -> [Integer]
    splitb [Integer]
    ns

        putH :: NonEmpty Integer -> NonEmpty Int
        putH :: NonEmpty Integer -> NonEmpty Int
    putH (Integer
    n:|[Integer]
    ns) = case Integer
    n Integer -> Integer -> (Integer, Integer)
    forall a. Integral a => a -> a -> (a, a)
    `quotRem` Integer
    maxPow10 of
                        (Integer
    x,Integer
    y)
                            | Int
    q Int -> Int -> Bool
    forall a. Ord a => a -> a -> Bool
    > Int
    0     -> Int
    q Int -> [Int] -> NonEmpty Int
    forall a. a -> [a] -> NonEmpty a
    :| Int
    r Int -> [Int] -> [Int]
    forall a. a -> [a] -> [a]
    :  [Integer] -> [Int]
    putB [Integer]
    ns
                            | Bool
    otherwise ->      Int
    r Int -> [Int] -> NonEmpty Int
    forall a. a -> [a] -> NonEmpty a
    :| [Integer] -> [Int]
    putB [Integer]
    ns
                            where q :: Int
    q = Integer -> Int
    forall a. Num a => Integer -> a
    fromInteger Integer
    x
                                  r :: Int
    r = Integer -> Int
    forall a. Num a => Integer -> a
    fromInteger Integer
    y

        putB :: [Integer] -> [Int]
        putB :: [Integer] -> [Int]
    putB []     = []
        putB (Integer
    n:[Integer]
    ns) = case Integer
    n Integer -> Integer -> (Integer, Integer)
    forall a. Integral a => a -> a -> (a, a)
    `quotRem` Integer
    maxPow10 of
                        (Integer
    q,Integer
    r) -> Integer -> Int
    forall a. Num a => Integer -> a
    fromInteger Integer
    q Int -> [Int] -> [Int]
    forall a. a -> [a] -> [a]
    : Integer -> Int
    forall a. Num a => Integer -> a
    fromInteger Integer
    r Int -> [Int] -> [Int]
    forall a. a -> [a] -> [a]
    : [Integer] -> [Int]
    putB [Integer]
    ns

    {-# INLINE intDecPadded #-}
    intDecPadded :: P.BoundedPrim Int
    intDecPadded :: BoundedPrim Int
    intDecPadded = FixedPrim Int -> BoundedPrim Int
    forall a. FixedPrim a -> BoundedPrim a
    P.liftFixedToBounded (FixedPrim Int -> BoundedPrim Int)
    -> FixedPrim Int -> BoundedPrim Int
    forall a b. (a -> b) -> a -> b
    $ FixedPrim Int -> FixedPrim Int -> FixedPrim Int
    forall a. a -> a -> a
    P.caseWordSize_32_64
        (Int -> (Int -> Ptr Word8 -> IO ()) -> FixedPrim Int
    forall a. Int -> (a -> Ptr Word8 -> IO ()) -> FixedPrim a
    P.fixedPrim  Int
    9 ((Int -> Ptr Word8 -> IO ()) -> FixedPrim Int)
    -> (Int -> Ptr Word8 -> IO ()) -> FixedPrim Int
    forall a b. (a -> b) -> a -> b
    $ CInt -> Ptr Word8 -> IO ()
    c_int_dec_padded9            (CInt -> Ptr Word8 -> IO ())
    -> (Int -> CInt) -> Int -> Ptr Word8 -> IO ()
    forall b c a. (b -> c) -> (a -> b) -> a -> c
    . Int -> CInt
    forall a b. (Integral a, Num b) => a -> b
    fromIntegral)
        (Int -> (Int -> Ptr Word8 -> IO ()) -> FixedPrim Int
    forall a. Int -> (a -> Ptr Word8 -> IO ()) -> FixedPrim a
    P.fixedPrim Int
    18 ((Int -> Ptr Word8 -> IO ()) -> FixedPrim Int)
    -> (Int -> Ptr Word8 -> IO ()) -> FixedPrim Int
    forall a b. (a -> b) -> a -> b
    $ CLLong -> Ptr Word8 -> IO ()
    c_long_long_int_dec_padded18 (CLLong -> Ptr Word8 -> IO ())
    -> (Int -> CLLong) -> Int -> Ptr Word8 -> IO ()
    forall b c a. (b -> c) -> (a -> b) -> a -> c
    . Int -> CLLong
    forall a b. (Integral a, Num b) => a -> b
    fromIntegral)