{-# OPTIONS_GHC -Wall -fwarn-tabs #-}
{-# LANGUAGE BangPatterns #-}
----------------------------------------------------------------
--                                                    2021.10.17
-- |
-- Module      :  Data.ByteString.Lex.Integral
-- Copyright   :  Copyright (c) 2010--2021 wren gayle romano
-- License     :  BSD2
-- Maintainer  :  wren@cpan.org
-- Stability   :  provisional
-- Portability :  BangPatterns
--
-- Functions for parsing and producing 'Integral' values from\/to
-- 'ByteString's based on the \"Char8\" encoding. That is, we assume
-- an ASCII-compatible encoding of alphanumeric characters.
--
-- /Since: 0.3.0/
----------------------------------------------------------------
module Data.ByteString.Lex.Integral
    (
    -- * General combinators
      readSigned
    -- , packSigned
    -- * Decimal conversions
    , readDecimal
    , readDecimal_
    , packDecimal
    -- TODO: asDecimal -- this will be really hard to make efficient...
    -- * Hexadecimal conversions
    , readHexadecimal
    , packHexadecimal
    , asHexadecimal
    -- * Octal conversions
    , readOctal
    , packOctal
    -- asOctal -- this will be really hard to make efficient...
    ) where

import           Data.ByteString          (ByteString)
import qualified Data.ByteString          as BS
import qualified Data.ByteString.Char8    as BS8 (pack)
import qualified Data.ByteString.Internal as BSI
import qualified Data.ByteString.Unsafe   as BSU
import           Data.Int
import           Data.Word
import           Data.Bits
import           Foreign.Ptr              (Ptr, plusPtr)
import qualified Foreign.ForeignPtr       as FFI (withForeignPtr)
import           Foreign.Storable         (peek, poke)
import           Data.ByteString.Lex.Internal

----------------------------------------------------------------
----- General

-- TODO: On the one hand, making this a combinator is "the right
-- thing to do" for generality. However, for performance critical
-- code, we could optimize away some extraneous guards if we just
-- provide both signed and unsigned versions of the
-- {read,pack}{Decimal,Octal,Hex} functions...

-- TODO: move to somewhere more general, shared by both Integral and Fractional
-- | Adjust a reading function to recognize an optional leading
-- sign. As with the other functions, we assume an ASCII-compatible
-- encoding of the sign characters.
readSigned
    :: (Num a)
    => (ByteString -> Maybe (a, ByteString))
    ->  ByteString -> Maybe (a, ByteString)
readSigned :: (ByteString -> Maybe (a, ByteString))
-> ByteString -> Maybe (a, ByteString)
readSigned ByteString -> Maybe (a, ByteString)
f ByteString
xs
    | ByteString -> Bool
BS.null ByteString
xs = Maybe (a, ByteString)
forall a. Maybe a
Nothing
    | Bool
otherwise  =
        case ByteString -> Word8
BSU.unsafeHead ByteString
xs of
        Word8
0x2D -> ByteString -> Maybe (a, ByteString)
f (ByteString -> ByteString
BSU.unsafeTail ByteString
xs) Maybe (a, ByteString)
-> ((a, ByteString) -> Maybe (a, ByteString))
-> Maybe (a, ByteString)
forall (m :: * -> *) a b. Monad m => m a -> (a -> m b) -> m b
>>= \(a
n, ByteString
ys) -> (a, ByteString) -> Maybe (a, ByteString)
forall (m :: * -> *) a. Monad m => a -> m a
return (a -> a
forall a. Num a => a -> a
negate a
n, ByteString
ys)
        Word8
0x2B -> ByteString -> Maybe (a, ByteString)
f (ByteString -> ByteString
BSU.unsafeTail ByteString
xs)
        Word8
_    -> ByteString -> Maybe (a, ByteString)
f ByteString
xs


----------------------------------------------------------------
----- Decimal

{-
-- We unroll this definition in order to reduce the number of conversions from native Int to the Integral type.
readDecimalSimple :: (Integral a) => ByteString -> Maybe (a, ByteString)
readDecimalSimple = start
    where
    -- This implementation is near verbatim from
    -- bytestring-0.9.1.7:Data.ByteString.Char8.readInt. We do
    -- remove the superstrictness by lifting the 'Just' so it can
    -- be returned after seeing the first byte. Do beware of the
    -- scope of 'fromIntegral', we want to avoid unnecessary
    -- 'Integral' operations and do as much as possible in 'Word8'.
    start xs
        | BS.null xs = Nothing
        | otherwise  =
            case BSU.unsafeHead xs of
            w | 0x39 >= w && w >= 0x30 ->
                    Just $ loop (fromIntegral (w - 0x30)) (BSU.unsafeTail xs)
              | otherwise -> Nothing

    loop !n !xs
        | BS.null xs = (n, BS.empty) -- not @xs@, to help GC
        | otherwise  =
            case BSU.unsafeHead xs of
            w | 0x39 >= w && w >= 0x30 ->
                    loop (n * 10 + fromIntegral (w - 0x30)) (BSU.unsafeTail xs)
              | otherwise -> (n,xs)
-}

-- | Read an unsigned\/non-negative integral value in ASCII decimal
-- format. Returns @Nothing@ if there is no integer at the beginning
-- of the string, otherwise returns @Just@ the integer read and the
-- remainder of the string.
--
-- If you are extremely concerned with performance, then it is more
-- performant to use this function at @Int@ or @Word@ and then to
-- call 'fromIntegral' to perform the conversion at the end. However,
-- doing this will make your code succeptible to overflow bugs if
-- the target type is larger than @Int@.
readDecimal :: (Integral a) => ByteString -> Maybe (a, ByteString)
{-# SPECIALIZE readDecimal ::
    ByteString -> Maybe (Int,     ByteString),
    ByteString -> Maybe (Int8,    ByteString),
    ByteString -> Maybe (Int16,   ByteString),
    ByteString -> Maybe (Int32,   ByteString),
    ByteString -> Maybe (Int64,   ByteString),
    ByteString -> Maybe (Integer, ByteString),
    ByteString -> Maybe (Word,    ByteString),
    ByteString -> Maybe (Word8,   ByteString),
    ByteString -> Maybe (Word16,  ByteString),
    ByteString -> Maybe (Word32,  ByteString),
    ByteString -> Maybe (Word64,  ByteString) #-}
readDecimal :: ByteString -> Maybe (a, ByteString)
readDecimal = ByteString -> Maybe (a, ByteString)
forall a. Integral a => ByteString -> Maybe (a, ByteString)
start
    where
    -- TODO: should we explicitly drop all leading zeros before we jump into the unrolled loop?
    start :: (Integral a) => ByteString -> Maybe (a, ByteString)
    start :: ByteString -> Maybe (a, ByteString)
start ByteString
xs
        | ByteString -> Bool
BS.null ByteString
xs = Maybe (a, ByteString)
forall a. Maybe a
Nothing
        | Bool
otherwise  =
            case ByteString -> Word8
BSU.unsafeHead ByteString
xs of
            Word8
w | Word8 -> Bool
isDecimal Word8
w -> (a, ByteString) -> Maybe (a, ByteString)
forall a. a -> Maybe a
Just ((a, ByteString) -> Maybe (a, ByteString))
-> (a, ByteString) -> Maybe (a, ByteString)
forall a b. (a -> b) -> a -> b
$ a -> ByteString -> (a, ByteString)
forall a. Integral a => a -> ByteString -> (a, ByteString)
loop0 (Word8 -> a
forall a. Integral a => Word8 -> a
toDigit Word8
w) (ByteString -> ByteString
BSU.unsafeTail ByteString
xs)
              | Bool
otherwise   -> Maybe (a, ByteString)
forall a. Maybe a
Nothing

    loop0 :: (Integral a) => a -> ByteString -> (a, ByteString)
    loop0 :: a -> ByteString -> (a, ByteString)
loop0 !a
m !ByteString
xs
        | ByteString -> Bool
BS.null ByteString
xs = (a
m, ByteString
BS.empty)
        | Bool
otherwise  =
            case ByteString -> Word8
BSU.unsafeHead ByteString
xs of
            Word8
w | Word8 -> Bool
isDecimal Word8
w -> a -> Int -> ByteString -> (a, ByteString)
forall a. Integral a => a -> Int -> ByteString -> (a, ByteString)
loop1 a
m (Word8 -> Int
forall a. Integral a => Word8 -> a
toDigit Word8
w) (ByteString -> ByteString
BSU.unsafeTail ByteString
xs)
              | Bool
otherwise   -> (a
m, ByteString
xs)

    loop1, loop2, loop3, loop4, loop5, loop6, loop7, loop8
        :: (Integral a) => a -> Int -> ByteString -> (a, ByteString)
    loop1 :: a -> Int -> ByteString -> (a, ByteString)
loop1 !a
m !Int
n !ByteString
xs
        | ByteString -> Bool
BS.null ByteString
xs = (a
ma -> a -> a
forall a. Num a => a -> a -> a
*a
10 a -> a -> a
forall a. Num a => a -> a -> a
+ Int -> a
forall a b. (Integral a, Num b) => a -> b
fromIntegral Int
n, ByteString
BS.empty)
        | Bool
otherwise  =
            case ByteString -> Word8
BSU.unsafeHead ByteString
xs of
            Word8
w | Word8 -> Bool
isDecimal Word8
w -> a -> Int -> ByteString -> (a, ByteString)
forall a. Integral a => a -> Int -> ByteString -> (a, ByteString)
loop2 a
m (Int -> Word8 -> Int
addDigit Int
n Word8
w) (ByteString -> ByteString
BSU.unsafeTail ByteString
xs)
              | Bool
otherwise   -> (a
ma -> a -> a
forall a. Num a => a -> a -> a
*a
10 a -> a -> a
forall a. Num a => a -> a -> a
+ Int -> a
forall a b. (Integral a, Num b) => a -> b
fromIntegral Int
n, ByteString
xs)
    loop2 :: a -> Int -> ByteString -> (a, ByteString)
loop2 !a
m !Int
n !ByteString
xs
        | ByteString -> Bool
BS.null ByteString
xs = (a
ma -> a -> a
forall a. Num a => a -> a -> a
*a
100 a -> a -> a
forall a. Num a => a -> a -> a
+ Int -> a
forall a b. (Integral a, Num b) => a -> b
fromIntegral Int
n, ByteString
BS.empty)
        | Bool
otherwise  =
            case ByteString -> Word8
BSU.unsafeHead ByteString
xs of
            Word8
w | Word8 -> Bool
isDecimal Word8
w -> a -> Int -> ByteString -> (a, ByteString)
forall a. Integral a => a -> Int -> ByteString -> (a, ByteString)
loop3 a
m (Int -> Word8 -> Int
addDigit Int
n Word8
w) (ByteString -> ByteString
BSU.unsafeTail ByteString
xs)
              | Bool
otherwise   -> (a
ma -> a -> a
forall a. Num a => a -> a -> a
*a
100 a -> a -> a
forall a. Num a => a -> a -> a
+ Int -> a
forall a b. (Integral a, Num b) => a -> b
fromIntegral Int
n, ByteString
xs)
    loop3 :: a -> Int -> ByteString -> (a, ByteString)
loop3 !a
m !Int
n !ByteString
xs
        | ByteString -> Bool
BS.null ByteString
xs = (a
ma -> a -> a
forall a. Num a => a -> a -> a
*a
1000 a -> a -> a
forall a. Num a => a -> a -> a
+ Int -> a
forall a b. (Integral a, Num b) => a -> b
fromIntegral Int
n, ByteString
BS.empty)
        | Bool
otherwise  =
            case ByteString -> Word8
BSU.unsafeHead ByteString
xs of
            Word8
w | Word8 -> Bool
isDecimal Word8
w -> a -> Int -> ByteString -> (a, ByteString)
forall a. Integral a => a -> Int -> ByteString -> (a, ByteString)
loop4 a
m (Int -> Word8 -> Int
addDigit Int
n Word8
w) (ByteString -> ByteString
BSU.unsafeTail ByteString
xs)
              | Bool
otherwise   -> (a
ma -> a -> a
forall a. Num a => a -> a -> a
*a
1000 a -> a -> a
forall a. Num a => a -> a -> a
+ Int -> a
forall a b. (Integral a, Num b) => a -> b
fromIntegral Int
n, ByteString
xs)
    loop4 :: a -> Int -> ByteString -> (a, ByteString)
loop4 !a
m !Int
n !ByteString
xs
        | ByteString -> Bool
BS.null ByteString
xs = (a
ma -> a -> a
forall a. Num a => a -> a -> a
*a
10000 a -> a -> a
forall a. Num a => a -> a -> a
+ Int -> a
forall a b. (Integral a, Num b) => a -> b
fromIntegral Int
n, ByteString
BS.empty)
        | Bool
otherwise  =
            case ByteString -> Word8
BSU.unsafeHead ByteString
xs of
            Word8
w | Word8 -> Bool
isDecimal Word8
w -> a -> Int -> ByteString -> (a, ByteString)
forall a. Integral a => a -> Int -> ByteString -> (a, ByteString)
loop5 a
m (Int -> Word8 -> Int
addDigit Int
n Word8
w) (ByteString -> ByteString
BSU.unsafeTail ByteString
xs)
              | Bool
otherwise   -> (a
ma -> a -> a
forall a. Num a => a -> a -> a
*a
10000 a -> a -> a
forall a. Num a => a -> a -> a
+ Int -> a
forall a b. (Integral a, Num b) => a -> b
fromIntegral Int
n, ByteString
xs)
    loop5 :: a -> Int -> ByteString -> (a, ByteString)
loop5 !a
m !Int
n !ByteString
xs
        | ByteString -> Bool
BS.null ByteString
xs = (a
ma -> a -> a
forall a. Num a => a -> a -> a
*a
100000 a -> a -> a
forall a. Num a => a -> a -> a
+ Int -> a
forall a b. (Integral a, Num b) => a -> b
fromIntegral Int
n, ByteString
BS.empty)
        | Bool
otherwise  =
            case ByteString -> Word8
BSU.unsafeHead ByteString
xs of
            Word8
w | Word8 -> Bool
isDecimal Word8
w -> a -> Int -> ByteString -> (a, ByteString)
forall a. Integral a => a -> Int -> ByteString -> (a, ByteString)
loop6 a
m (Int -> Word8 -> Int
addDigit Int
n Word8
w) (ByteString -> ByteString
BSU.unsafeTail ByteString
xs)
              | Bool
otherwise   -> (a
ma -> a -> a
forall a. Num a => a -> a -> a
*a
100000 a -> a -> a
forall a. Num a => a -> a -> a
+ Int -> a
forall a b. (Integral a, Num b) => a -> b
fromIntegral Int
n, ByteString
xs)
    loop6 :: a -> Int -> ByteString -> (a, ByteString)
loop6 !a
m !Int
n !ByteString
xs
        | ByteString -> Bool
BS.null ByteString
xs = (a
ma -> a -> a
forall a. Num a => a -> a -> a
*a
1000000 a -> a -> a
forall a. Num a => a -> a -> a
+ Int -> a
forall a b. (Integral a, Num b) => a -> b
fromIntegral Int
n, ByteString
BS.empty)
        | Bool
otherwise  =
            case ByteString -> Word8
BSU.unsafeHead ByteString
xs of
            Word8
w | Word8 -> Bool
isDecimal Word8
w -> a -> Int -> ByteString -> (a, ByteString)
forall a. Integral a => a -> Int -> ByteString -> (a, ByteString)
loop7 a
m (Int -> Word8 -> Int
addDigit Int
n Word8
w) (ByteString -> ByteString
BSU.unsafeTail ByteString
xs)
              | Bool
otherwise   -> (a
ma -> a -> a
forall a. Num a => a -> a -> a
*a
1000000 a -> a -> a
forall a. Num a => a -> a -> a
+ Int -> a
forall a b. (Integral a, Num b) => a -> b
fromIntegral Int
n, ByteString
xs)
    loop7 :: a -> Int -> ByteString -> (a, ByteString)
loop7 !a
m !Int
n !ByteString
xs
        | ByteString -> Bool
BS.null ByteString
xs = (a
ma -> a -> a
forall a. Num a => a -> a -> a
*a
10000000 a -> a -> a
forall a. Num a => a -> a -> a
+ Int -> a
forall a b. (Integral a, Num b) => a -> b
fromIntegral Int
n, ByteString
BS.empty)
        | Bool
otherwise  =
            case ByteString -> Word8
BSU.unsafeHead ByteString
xs of
            Word8
w | Word8 -> Bool
isDecimal Word8
w -> a -> Int -> ByteString -> (a, ByteString)
forall a. Integral a => a -> Int -> ByteString -> (a, ByteString)
loop8 a
m (Int -> Word8 -> Int
addDigit Int
n Word8
w) (ByteString -> ByteString
BSU.unsafeTail ByteString
xs)
              | Bool
otherwise   -> (a
ma -> a -> a
forall a. Num a => a -> a -> a
*a
10000000 a -> a -> a
forall a. Num a => a -> a -> a
+ Int -> a
forall a b. (Integral a, Num b) => a -> b
fromIntegral Int
n, ByteString
xs)
    loop8 :: a -> Int -> ByteString -> (a, ByteString)
loop8 !a
m !Int
n !ByteString
xs
        | ByteString -> Bool
BS.null ByteString
xs = (a
ma -> a -> a
forall a. Num a => a -> a -> a
*a
100000000 a -> a -> a
forall a. Num a => a -> a -> a
+ Int -> a
forall a b. (Integral a, Num b) => a -> b
fromIntegral Int
n, ByteString
BS.empty)
        | Bool
otherwise  =
            case ByteString -> Word8
BSU.unsafeHead ByteString
xs of
            Word8
w | Word8 -> Bool
isDecimal Word8
w -> a -> ByteString -> (a, ByteString)
forall a. Integral a => a -> ByteString -> (a, ByteString)
loop0
                    (a
ma -> a -> a
forall a. Num a => a -> a -> a
*a
1000000000 a -> a -> a
forall a. Num a => a -> a -> a
+ Int -> a
forall a b. (Integral a, Num b) => a -> b
fromIntegral (Int -> Word8 -> Int
addDigit Int
n Word8
w))
                    (ByteString -> ByteString
BSU.unsafeTail ByteString
xs)
              | Bool
otherwise   -> (a
ma -> a -> a
forall a. Num a => a -> a -> a
*a
100000000 a -> a -> a
forall a. Num a => a -> a -> a
+ Int -> a
forall a b. (Integral a, Num b) => a -> b
fromIntegral Int
n, ByteString
xs)

----------------------------------------------------------------

-- | A variant of 'readDecimal' which does not return the tail of
-- the string, and returns @0@ instead of @Nothing@. This is twice
-- as fast for 'Int64' on 32-bit systems, but has identical performance
-- to 'readDecimal' for all other types and architectures.
--
-- /Since: 0.4.0/
readDecimal_ :: (Integral a) => ByteString -> a
{-# SPECIALIZE readDecimal_ ::
    ByteString -> Int,
    ByteString -> Int8,
    ByteString -> Int16,
    ByteString -> Int32,
    ByteString -> Int64,
    ByteString -> Integer,
    ByteString -> Word,
    ByteString -> Word8,
    ByteString -> Word16,
    ByteString -> Word32,
    ByteString -> Word64 #-}
readDecimal_ :: ByteString -> a
readDecimal_ = ByteString -> a
forall p. Integral p => ByteString -> p
start
    where
    start :: ByteString -> p
start ByteString
xs
        | ByteString -> Bool
BS.null ByteString
xs = p
0
        | Bool
otherwise  =
            case ByteString -> Word8
BSU.unsafeHead ByteString
xs of
            Word8
w | Word8 -> Bool
isDecimal Word8
w -> p -> ByteString -> p
forall a. Integral a => a -> ByteString -> a
loop0 (Word8 -> p
forall a. Integral a => Word8 -> a
toDigit Word8
w) (ByteString -> ByteString
BSU.unsafeTail ByteString
xs)
              | Bool
otherwise   -> p
0

    loop0 :: (Integral a) => a -> ByteString -> a
    loop0 :: a -> ByteString -> a
loop0 !a
m !ByteString
xs
        | ByteString -> Bool
BS.null ByteString
xs = a
m
        | Bool
otherwise  =
            case ByteString -> Word8
BSU.unsafeHead ByteString
xs of
            Word8
w | Word8 -> Bool
isDecimal Word8
w -> a -> Int -> ByteString -> a
forall a. Integral a => a -> Int -> ByteString -> a
loop1 a
m (Word8 -> Int
forall a. Integral a => Word8 -> a
toDigit Word8
w) (ByteString -> ByteString
BSU.unsafeTail ByteString
xs)
              | Bool
otherwise   -> a
m

    loop1, loop2, loop3, loop4, loop5, loop6, loop7, loop8
        :: (Integral a) => a -> Int -> ByteString -> a
    loop1 :: a -> Int -> ByteString -> a
loop1 !a
m !Int
n !ByteString
xs
        | ByteString -> Bool
BS.null ByteString
xs = a
ma -> a -> a
forall a. Num a => a -> a -> a
*a
10 a -> a -> a
forall a. Num a => a -> a -> a
+ Int -> a
forall a b. (Integral a, Num b) => a -> b
fromIntegral Int
n
        | Bool
otherwise  =
            case ByteString -> Word8
BSU.unsafeHead ByteString
xs of
            Word8
w | Word8 -> Bool
isDecimal Word8
w -> a -> Int -> ByteString -> a
forall a. Integral a => a -> Int -> ByteString -> a
loop2 a
m (Int -> Word8 -> Int
addDigit Int
n Word8
w) (ByteString -> ByteString
BSU.unsafeTail ByteString
xs)
              | Bool
otherwise   -> a
ma -> a -> a
forall a. Num a => a -> a -> a
*a
10 a -> a -> a
forall a. Num a => a -> a -> a
+ Int -> a
forall a b. (Integral a, Num b) => a -> b
fromIntegral Int
n
    loop2 :: a -> Int -> ByteString -> a
loop2 !a
m !Int
n !ByteString
xs
        | ByteString -> Bool
BS.null ByteString
xs = a
ma -> a -> a
forall a. Num a => a -> a -> a
*a
100 a -> a -> a
forall a. Num a => a -> a -> a
+ Int -> a
forall a b. (Integral a, Num b) => a -> b
fromIntegral Int
n
        | Bool
otherwise  =
            case ByteString -> Word8
BSU.unsafeHead ByteString
xs of
            Word8
w | Word8 -> Bool
isDecimal Word8
w -> a -> Int -> ByteString -> a
forall a. Integral a => a -> Int -> ByteString -> a
loop3 a
m (Int -> Word8 -> Int
addDigit Int
n Word8
w) (ByteString -> ByteString
BSU.unsafeTail ByteString
xs)
              | Bool
otherwise   -> a
ma -> a -> a
forall a. Num a => a -> a -> a
*a
100 a -> a -> a
forall a. Num a => a -> a -> a
+ Int -> a
forall a b. (Integral a, Num b) => a -> b
fromIntegral Int
n
    loop3 :: a -> Int -> ByteString -> a
loop3 !a
m !Int
n !ByteString
xs
        | ByteString -> Bool
BS.null ByteString
xs = a
ma -> a -> a
forall a. Num a => a -> a -> a
*a
1000 a -> a -> a
forall a. Num a => a -> a -> a
+ Int -> a
forall a b. (Integral a, Num b) => a -> b
fromIntegral Int
n
        | Bool
otherwise  =
            case ByteString -> Word8
BSU.unsafeHead ByteString
xs of
            Word8
w | Word8 -> Bool
isDecimal Word8
w -> a -> Int -> ByteString -> a
forall a. Integral a => a -> Int -> ByteString -> a
loop4 a
m (Int -> Word8 -> Int
addDigit Int
n Word8
w) (ByteString -> ByteString
BSU.unsafeTail ByteString
xs)
              | Bool
otherwise   -> a
ma -> a -> a
forall a. Num a => a -> a -> a
*a
1000 a -> a -> a
forall a. Num a => a -> a -> a
+ Int -> a
forall a b. (Integral a, Num b) => a -> b
fromIntegral Int
n
    loop4 :: a -> Int -> ByteString -> a
loop4 !a
m !Int
n !ByteString
xs
        | ByteString -> Bool
BS.null ByteString
xs = a
ma -> a -> a
forall a. Num a => a -> a -> a
*a
10000 a -> a -> a
forall a. Num a => a -> a -> a
+ Int -> a
forall a b. (Integral a, Num b) => a -> b
fromIntegral Int
n
        | Bool
otherwise  =
            case ByteString -> Word8
BSU.unsafeHead ByteString
xs of
            Word8
w | Word8 -> Bool
isDecimal Word8
w -> a -> Int -> ByteString -> a
forall a. Integral a => a -> Int -> ByteString -> a
loop5 a
m (Int -> Word8 -> Int
addDigit Int
n Word8
w) (ByteString -> ByteString
BSU.unsafeTail ByteString
xs)
              | Bool
otherwise   -> a
ma -> a -> a
forall a. Num a => a -> a -> a
*a
10000 a -> a -> a
forall a. Num a => a -> a -> a
+ Int -> a
forall a b. (Integral a, Num b) => a -> b
fromIntegral Int
n
    loop5 :: a -> Int -> ByteString -> a
loop5 !a
m !Int
n !ByteString
xs
        | ByteString -> Bool
BS.null ByteString
xs = a
ma -> a -> a
forall a. Num a => a -> a -> a
*a
100000 a -> a -> a
forall a. Num a => a -> a -> a
+ Int -> a
forall a b. (Integral a, Num b) => a -> b
fromIntegral Int
n
        | Bool
otherwise  =
            case ByteString -> Word8
BSU.unsafeHead ByteString
xs of
            Word8
w | Word8 -> Bool
isDecimal Word8
w -> a -> Int -> ByteString -> a
forall a. Integral a => a -> Int -> ByteString -> a
loop6 a
m (Int -> Word8 -> Int
addDigit Int
n Word8
w) (ByteString -> ByteString
BSU.unsafeTail ByteString
xs)
              | Bool
otherwise   -> a
ma -> a -> a
forall a. Num a => a -> a -> a
*a
100000 a -> a -> a
forall a. Num a => a -> a -> a
+ Int -> a
forall a b. (Integral a, Num b) => a -> b
fromIntegral Int
n
    loop6 :: a -> Int -> ByteString -> a
loop6 !a
m !Int
n !ByteString
xs
        | ByteString -> Bool
BS.null ByteString
xs = a
ma -> a -> a
forall a. Num a => a -> a -> a
*a
1000000 a -> a -> a
forall a. Num a => a -> a -> a
+ Int -> a
forall a b. (Integral a, Num b) => a -> b
fromIntegral Int
n
        | Bool
otherwise  =
            case ByteString -> Word8
BSU.unsafeHead ByteString
xs of
            Word8
w | Word8 -> Bool
isDecimal Word8
w -> a -> Int -> ByteString -> a
forall a. Integral a => a -> Int -> ByteString -> a
loop7 a
m (Int -> Word8 -> Int
addDigit Int
n Word8
w) (ByteString -> ByteString
BSU.unsafeTail ByteString
xs)
              | Bool
otherwise   -> a
ma -> a -> a
forall a. Num a => a -> a -> a
*a
1000000 a -> a -> a
forall a. Num a => a -> a -> a
+ Int -> a
forall a b. (Integral a, Num b) => a -> b
fromIntegral Int
n
    loop7 :: a -> Int -> ByteString -> a
loop7 !a
m !Int
n !ByteString
xs
        | ByteString -> Bool
BS.null ByteString
xs = a
ma -> a -> a
forall a. Num a => a -> a -> a
*a
10000000 a -> a -> a
forall a. Num a => a -> a -> a
+ Int -> a
forall a b. (Integral a, Num b) => a -> b
fromIntegral Int
n
        | Bool
otherwise  =
            case ByteString -> Word8
BSU.unsafeHead ByteString
xs of
            Word8
w | Word8 -> Bool
isDecimal Word8
w -> a -> Int -> ByteString -> a
forall a. Integral a => a -> Int -> ByteString -> a
loop8 a
m (Int -> Word8 -> Int
addDigit Int
n Word8
w) (ByteString -> ByteString
BSU.unsafeTail ByteString
xs)
              | Bool
otherwise   -> a
ma -> a -> a
forall a. Num a => a -> a -> a
*a
10000000 a -> a -> a
forall a. Num a => a -> a -> a
+ Int -> a
forall a b. (Integral a, Num b) => a -> b
fromIntegral Int
n
    loop8 :: a -> Int -> ByteString -> a
loop8 !a
m !Int
n !ByteString
xs
        | ByteString -> Bool
BS.null ByteString
xs = a
ma -> a -> a
forall a. Num a => a -> a -> a
*a
100000000 a -> a -> a
forall a. Num a => a -> a -> a
+ Int -> a
forall a b. (Integral a, Num b) => a -> b
fromIntegral Int
n
        | Bool
otherwise  =
            case ByteString -> Word8
BSU.unsafeHead ByteString
xs of
            Word8
w | Word8 -> Bool
isDecimal Word8
w -> a -> ByteString -> a
forall a. Integral a => a -> ByteString -> a
loop0
                    (a
ma -> a -> a
forall a. Num a => a -> a -> a
*a
1000000000 a -> a -> a
forall a. Num a => a -> a -> a
+ Int -> a
forall a b. (Integral a, Num b) => a -> b
fromIntegral (Int -> Word8 -> Int
addDigit Int
n Word8
w))
                    (ByteString -> ByteString
BSU.unsafeTail ByteString
xs)
              | Bool
otherwise   -> a
ma -> a -> a
forall a. Num a => a -> a -> a
*a
100000000 a -> a -> a
forall a. Num a => a -> a -> a
+ Int -> a
forall a b. (Integral a, Num b) => a -> b
fromIntegral Int
n

----------------------------------------------------------------
-- | Convert a non-negative integer into an (unsigned) ASCII decimal
-- string. Returns @Nothing@ on negative inputs.
packDecimal :: (Integral a) => a -> Maybe ByteString
{-# INLINE packDecimal #-}
packDecimal :: a -> Maybe ByteString
packDecimal a
n
    | a
n a -> a -> Bool
forall a. Ord a => a -> a -> Bool
< a
0     = Maybe ByteString
forall a. Maybe a
Nothing
    | Bool
otherwise = ByteString -> Maybe ByteString
forall a. a -> Maybe a
Just (a -> ByteString
forall a. Integral a => a -> ByteString
unsafePackDecimal a
n)


-- This implementation is modified from:
-- <http://www.serpentine.com/blog/2013/03/20/whats-good-for-c-is-good-for-haskell/>
-- See the banchmarks for implementation details.
-- BUG: the additional guard in 'numDecimalDigits' results in a 3x slowdown!!
--
-- | Convert a non-negative integer into an (unsigned) ASCII decimal
-- string. This function is unsafe to use on negative inputs.
unsafePackDecimal :: (Integral a) => a -> ByteString
{-# SPECIALIZE unsafePackDecimal ::
    Int     -> ByteString,
    Int8    -> ByteString,
    Int16   -> ByteString,
    Int32   -> ByteString,
    Int64   -> ByteString,
    Integer -> ByteString,
    Word    -> ByteString,
    Word8   -> ByteString,
    Word16  -> ByteString,
    Word32  -> ByteString,
    Word64  -> ByteString #-}
unsafePackDecimal :: a -> ByteString
unsafePackDecimal a
n0 =
    let size :: Int
size = a -> Int
forall a. Integral a => a -> Int
numDecimalDigits a
n0
    in  Int -> (Ptr Word8 -> IO ()) -> ByteString
BSI.unsafeCreate Int
size ((Ptr Word8 -> IO ()) -> ByteString)
-> (Ptr Word8 -> IO ()) -> ByteString
forall a b. (a -> b) -> a -> b
$ \Ptr Word8
p0 -> a -> Ptr Word8 -> IO ()
forall a. Integral a => a -> Ptr Word8 -> IO ()
loop a
n0 (Ptr Word8
p0 Ptr Word8 -> Int -> Ptr Word8
forall a b. Ptr a -> Int -> Ptr b
`plusPtr` (Int
size Int -> Int -> Int
forall a. Num a => a -> a -> a
- Int
1))
    where
    getDigit :: Int -> Word8
getDigit = ByteString -> Int -> Word8
BSU.unsafeIndex ByteString
packDecimal_digits

    loop :: a -> Ptr Word8 -> IO ()
loop !a
n !Ptr Word8
p
        | a
n a -> a -> Bool
forall a. Ord a => a -> a -> Bool
>= a
100  = do
            let (a
q,a
r) = a
n a -> a -> (a, a)
forall a. Integral a => a -> a -> (a, a)
`quotRem` a
100
            a -> Ptr Word8 -> IO ()
forall a. Integral a => a -> Ptr Word8 -> IO ()
write2 a
r Ptr Word8
p
            a -> Ptr Word8 -> IO ()
loop   a
q (Ptr Word8
p Ptr Word8 -> Int -> Ptr Word8
forall a b. Ptr a -> Int -> Ptr b
`plusPtr` Int -> Int
forall a. Num a => a -> a
negate Int
2)
        | a
n a -> a -> Bool
forall a. Ord a => a -> a -> Bool
>= a
10   = a -> Ptr Word8 -> IO ()
forall a. Integral a => a -> Ptr Word8 -> IO ()
write2 a
n Ptr Word8
p
        | Bool
otherwise = Ptr Word8 -> Word8 -> IO ()
forall a. Storable a => Ptr a -> a -> IO ()
poke Ptr Word8
p (Word8
0x30 Word8 -> Word8 -> Word8
forall a. Num a => a -> a -> a
+ a -> Word8
forall a b. (Integral a, Num b) => a -> b
fromIntegral a
n)

    write2 :: a -> Ptr Word8 -> IO ()
write2 !a
i0 !Ptr Word8
p = do
        let i :: Int
i = a -> Int
forall a b. (Integral a, Num b) => a -> b
fromIntegral a
i0; j :: Int
j = Int
i Int -> Int -> Int
forall a. Num a => a -> a -> a
+ Int
i
        Ptr Word8 -> Word8 -> IO ()
forall a. Storable a => Ptr a -> a -> IO ()
poke Ptr Word8
p                      (Int -> Word8
getDigit (Int -> Word8) -> Int -> Word8
forall a b. (a -> b) -> a -> b
$! Int
j Int -> Int -> Int
forall a. Num a => a -> a -> a
+ Int
1)
        Ptr Word8 -> Word8 -> IO ()
forall a. Storable a => Ptr a -> a -> IO ()
poke (Ptr Word8
p Ptr Word8 -> Int -> Ptr Word8
forall a b. Ptr a -> Int -> Ptr b
`plusPtr` Int -> Int
forall a. Num a => a -> a
negate Int
1) (Int -> Word8
getDigit Int
j)

-- TODO(2021-10-23): We might should replace this with the 'Addr#'
--   hack that newer Bytestring uses for hexadecimal stuff:
--   <https://github.com/haskell/bytestring/pull/418>
packDecimal_digits :: ByteString
{-# NOINLINE packDecimal_digits #-}
packDecimal_digits :: ByteString
packDecimal_digits = String -> ByteString
BS8.pack
    String
"0001020304050607080910111213141516171819\
    \2021222324252627282930313233343536373839\
    \4041424344454647484950515253545556575859\
    \6061626364656667686970717273747576777879\
    \8081828384858687888990919293949596979899"

----------------------------------------------------------------
----------------------------------------------------------------
----- Hexadecimal

-- | Read a non-negative integral value in ASCII hexadecimal format.
-- Returns @Nothing@ if there is no integer at the beginning of the
-- string, otherwise returns @Just@ the integer read and the remainder
-- of the string.
--
-- This function does not recognize the various hexadecimal sigils
-- like \"0x\", but because there are so many different variants,
-- those are best handled by helper functions which then use this
-- function for the actual numerical parsing. This function recognizes
-- both upper-case, lower-case, and mixed-case hexadecimal.
readHexadecimal :: (Integral a) => ByteString -> Maybe (a, ByteString)
{-# SPECIALIZE readHexadecimal ::
    ByteString -> Maybe (Int,     ByteString),
    ByteString -> Maybe (Int8,    ByteString),
    ByteString -> Maybe (Int16,   ByteString),
    ByteString -> Maybe (Int32,   ByteString),
    ByteString -> Maybe (Int64,   ByteString),
    ByteString -> Maybe (Integer, ByteString),
    ByteString -> Maybe (Word,    ByteString),
    ByteString -> Maybe (Word8,   ByteString),
    ByteString -> Maybe (Word16,  ByteString),
    ByteString -> Maybe (Word32,  ByteString),
    ByteString -> Maybe (Word64,  ByteString) #-}
readHexadecimal :: ByteString -> Maybe (a, ByteString)
readHexadecimal = ByteString -> Maybe (a, ByteString)
forall a. Num a => ByteString -> Maybe (a, ByteString)
start
    where
    -- TODO: Would it be worth trying to do the magichash trick
    -- used by Warp here? It'd really help remove branch prediction
    -- issues etc.
    --
    -- Beware the urge to make this code prettier, cf 'readDecimal'.
    start :: ByteString -> Maybe (a, ByteString)
start ByteString
xs
        | ByteString -> Bool
BS.null ByteString
xs = Maybe (a, ByteString)
forall a. Maybe a
Nothing
        | Bool
otherwise  =
            case ByteString -> Word8
BSU.unsafeHead ByteString
xs of
            Word8
w | Word8
0x39 Word8 -> Word8 -> Bool
forall a. Ord a => a -> a -> Bool
>= Word8
w Bool -> Bool -> Bool
&& Word8
w Word8 -> Word8 -> Bool
forall a. Ord a => a -> a -> Bool
>= Word8
0x30 ->
                    (a, ByteString) -> Maybe (a, ByteString)
forall a. a -> Maybe a
Just ((a, ByteString) -> Maybe (a, ByteString))
-> (a, ByteString) -> Maybe (a, ByteString)
forall a b. (a -> b) -> a -> b
$ a -> ByteString -> (a, ByteString)
forall a. Num a => a -> ByteString -> (a, ByteString)
loop (Word8 -> a
forall a b. (Integral a, Num b) => a -> b
fromIntegral (Word8
w Word8 -> Word8 -> Word8
forall a. Num a => a -> a -> a
- Word8
0x30))  (ByteString -> ByteString
BSU.unsafeTail ByteString
xs)
              | Word8
0x46 Word8 -> Word8 -> Bool
forall a. Ord a => a -> a -> Bool
>= Word8
w Bool -> Bool -> Bool
&& Word8
w Word8 -> Word8 -> Bool
forall a. Ord a => a -> a -> Bool
>= Word8
0x41 ->
                    (a, ByteString) -> Maybe (a, ByteString)
forall a. a -> Maybe a
Just ((a, ByteString) -> Maybe (a, ByteString))
-> (a, ByteString) -> Maybe (a, ByteString)
forall a b. (a -> b) -> a -> b
$ a -> ByteString -> (a, ByteString)
forall a. Num a => a -> ByteString -> (a, ByteString)
loop (Word8 -> a
forall a b. (Integral a, Num b) => a -> b
fromIntegral (Word8
wWord8 -> Word8 -> Word8
forall a. Num a => a -> a -> a
-Word8
0x41Word8 -> Word8 -> Word8
forall a. Num a => a -> a -> a
+Word8
10)) (ByteString -> ByteString
BSU.unsafeTail ByteString
xs)
              | Word8
0x66 Word8 -> Word8 -> Bool
forall a. Ord a => a -> a -> Bool
>= Word8
w Bool -> Bool -> Bool
&& Word8
w Word8 -> Word8 -> Bool
forall a. Ord a => a -> a -> Bool
>= Word8
0x61 ->
                    (a, ByteString) -> Maybe (a, ByteString)
forall a. a -> Maybe a
Just ((a, ByteString) -> Maybe (a, ByteString))
-> (a, ByteString) -> Maybe (a, ByteString)
forall a b. (a -> b) -> a -> b
$ a -> ByteString -> (a, ByteString)
forall a. Num a => a -> ByteString -> (a, ByteString)
loop (Word8 -> a
forall a b. (Integral a, Num b) => a -> b
fromIntegral (Word8
wWord8 -> Word8 -> Word8
forall a. Num a => a -> a -> a
-Word8
0x61Word8 -> Word8 -> Word8
forall a. Num a => a -> a -> a
+Word8
10)) (ByteString -> ByteString
BSU.unsafeTail ByteString
xs)
              | Bool
otherwise -> Maybe (a, ByteString)
forall a. Maybe a
Nothing

    loop :: a -> ByteString -> (a, ByteString)
loop !a
n !ByteString
xs
        | ByteString -> Bool
BS.null ByteString
xs = (a
n, ByteString
BS.empty) -- not @xs@, to help GC
        | Bool
otherwise  =
            case ByteString -> Word8
BSU.unsafeHead ByteString
xs of
            Word8
w | Word8
0x39 Word8 -> Word8 -> Bool
forall a. Ord a => a -> a -> Bool
>= Word8
w Bool -> Bool -> Bool
&& Word8
w Word8 -> Word8 -> Bool
forall a. Ord a => a -> a -> Bool
>= Word8
0x30 ->
                    a -> ByteString -> (a, ByteString)
loop (a
na -> a -> a
forall a. Num a => a -> a -> a
*a
16 a -> a -> a
forall a. Num a => a -> a -> a
+ Word8 -> a
forall a b. (Integral a, Num b) => a -> b
fromIntegral (Word8
w Word8 -> Word8 -> Word8
forall a. Num a => a -> a -> a
- Word8
0x30))  (ByteString -> ByteString
BSU.unsafeTail ByteString
xs)
              | Word8
0x46 Word8 -> Word8 -> Bool
forall a. Ord a => a -> a -> Bool
>= Word8
w Bool -> Bool -> Bool
&& Word8
w Word8 -> Word8 -> Bool
forall a. Ord a => a -> a -> Bool
>= Word8
0x41 ->
                    a -> ByteString -> (a, ByteString)
loop (a
na -> a -> a
forall a. Num a => a -> a -> a
*a
16 a -> a -> a
forall a. Num a => a -> a -> a
+ Word8 -> a
forall a b. (Integral a, Num b) => a -> b
fromIntegral (Word8
wWord8 -> Word8 -> Word8
forall a. Num a => a -> a -> a
-Word8
0x41Word8 -> Word8 -> Word8
forall a. Num a => a -> a -> a
+Word8
10)) (ByteString -> ByteString
BSU.unsafeTail ByteString
xs)
              | Word8
0x66 Word8 -> Word8 -> Bool
forall a. Ord a => a -> a -> Bool
>= Word8
w Bool -> Bool -> Bool
&& Word8
w Word8 -> Word8 -> Bool
forall a. Ord a => a -> a -> Bool
>= Word8
0x61 ->
                    a -> ByteString -> (a, ByteString)
loop (a
na -> a -> a
forall a. Num a => a -> a -> a
*a
16 a -> a -> a
forall a. Num a => a -> a -> a
+ Word8 -> a
forall a b. (Integral a, Num b) => a -> b
fromIntegral (Word8
wWord8 -> Word8 -> Word8
forall a. Num a => a -> a -> a
-Word8
0x61Word8 -> Word8 -> Word8
forall a. Num a => a -> a -> a
+Word8
10)) (ByteString -> ByteString
BSU.unsafeTail ByteString
xs)
              | Bool
otherwise -> (a
n,ByteString
xs)


-- | Convert a non-negative integer into a lower-case ASCII hexadecimal
-- string. Returns @Nothing@ on negative inputs.
packHexadecimal :: (Integral a) => a -> Maybe ByteString
{-# INLINE packHexadecimal #-}
packHexadecimal :: a -> Maybe ByteString
packHexadecimal a
n
    | a
n a -> a -> Bool
forall a. Ord a => a -> a -> Bool
< a
0     = Maybe ByteString
forall a. Maybe a
Nothing
    | Bool
otherwise = ByteString -> Maybe ByteString
forall a. a -> Maybe a
Just (a -> ByteString
forall a. Integral a => a -> ByteString
unsafePackHexadecimal a
n)


-- | Convert a non-negative integer into a lower-case ASCII hexadecimal
-- string. This function is unsafe to use on negative inputs.
unsafePackHexadecimal :: (Integral a) => a -> ByteString
{-# SPECIALIZE unsafePackHexadecimal ::
    Int     -> ByteString,
    Int8    -> ByteString,
    Int16   -> ByteString,
    Int32   -> ByteString,
    Int64   -> ByteString,
    Integer -> ByteString,
    Word    -> ByteString,
    Word8   -> ByteString,
    Word16  -> ByteString,
    Word32  -> ByteString,
    Word64  -> ByteString #-}
unsafePackHexadecimal :: a -> ByteString
unsafePackHexadecimal a
n0 =
    let size :: Int
size = Int -> Integer -> Int
forall a. (Integral a, Bits a) => Int -> a -> Int
numTwoPowerDigits Int
4 (a -> Integer
forall a. Integral a => a -> Integer
toInteger a
n0) -- for Bits
    in  Int -> (Ptr Word8 -> IO ()) -> ByteString
BSI.unsafeCreate Int
size ((Ptr Word8 -> IO ()) -> ByteString)
-> (Ptr Word8 -> IO ()) -> ByteString
forall a b. (a -> b) -> a -> b
$ \Ptr Word8
p0 ->
            a -> Ptr Word8 -> IO ()
forall a. Integral a => a -> Ptr Word8 -> IO ()
loop a
n0 (Ptr Word8
p0 Ptr Word8 -> Int -> Ptr Word8
forall a b. Ptr a -> Int -> Ptr b
`plusPtr` (Int
size Int -> Int -> Int
forall a. Num a => a -> a -> a
- Int
1))
    where
    -- TODO: benchmark using @hexDigits@ vs using direct manipulations.
    loop :: (Integral a) => a -> Ptr Word8 -> IO ()
    loop :: a -> Ptr Word8 -> IO ()
loop a
n Ptr Word8
p
        | a
n a -> a -> Bool
forall a. Ord a => a -> a -> Bool
<= a
15   = do
            Ptr Word8 -> Word8 -> IO ()
forall a. Storable a => Ptr a -> a -> IO ()
poke Ptr Word8
p (ByteString -> Int -> Word8
BSU.unsafeIndex ByteString
hexDigits (a -> Int
forall a b. (Integral a, Num b) => a -> b
fromIntegral a
n Int -> Int -> Int
forall a. Bits a => a -> a -> a
.&. Int
0x0F))
        | Bool
otherwise = do
            let (a
q,a
r) = a
n a -> a -> (a, a)
forall a. Integral a => a -> a -> (a, a)
`quotRem` a
16
            Ptr Word8 -> Word8 -> IO ()
forall a. Storable a => Ptr a -> a -> IO ()
poke Ptr Word8
p (ByteString -> Int -> Word8
BSU.unsafeIndex ByteString
hexDigits (a -> Int
forall a b. (Integral a, Num b) => a -> b
fromIntegral a
r Int -> Int -> Int
forall a. Bits a => a -> a -> a
.&. Int
0x0F))
            a -> Ptr Word8 -> IO ()
forall a. Integral a => a -> Ptr Word8 -> IO ()
loop a
q (Ptr Word8
p Ptr Word8 -> Int -> Ptr Word8
forall a b. Ptr a -> Int -> Ptr b
`plusPtr` Int -> Int
forall a. Num a => a -> a
negate Int
1)


-- Inspired by, <http://forums.xkcd.com/viewtopic.php?f=11&t=16666&p=553936>
-- | Convert a bitvector into a lower-case ASCII hexadecimal string.
-- This is helpful for visualizing raw binary data, rather than for
-- parsing as such.
asHexadecimal :: ByteString -> ByteString
asHexadecimal :: ByteString -> ByteString
asHexadecimal = ByteString -> ByteString
start
    where
    start :: ByteString -> ByteString
start ByteString
buf
        | ByteString -> Int
BS.length ByteString
buf Int -> Int -> Bool
forall a. Ord a => a -> a -> Bool
> Int
forall a. Bounded a => a
maxBound Int -> Int -> Int
forall a. Integral a => a -> a -> a
`quot` Int
2 =
            String -> ByteString
forall a. HasCallStack => String -> a
error String
_asHexadecimal_overflow
        | Bool
otherwise =
            Int -> (Ptr Word8 -> IO ()) -> ByteString
BSI.unsafeCreate (Int
2 Int -> Int -> Int
forall a. Num a => a -> a -> a
* ByteString -> Int
BS.length ByteString
buf) ((Ptr Word8 -> IO ()) -> ByteString)
-> (Ptr Word8 -> IO ()) -> ByteString
forall a b. (a -> b) -> a -> b
$ \Ptr Word8
p0 -> do
                Ptr Word8
_ <- (Ptr Word8 -> Word8 -> IO (Ptr Word8))
-> Ptr Word8 -> ByteString -> IO (Ptr Word8)
forall a. (a -> Word8 -> IO a) -> a -> ByteString -> IO a
foldIO Ptr Word8 -> Word8 -> IO (Ptr Word8)
step Ptr Word8
p0 ByteString
buf
                () -> IO ()
forall (m :: * -> *) a. Monad m => a -> m a
return () -- needed for type checking

    step :: Ptr Word8 -> Word8 -> IO (Ptr Word8)
    step :: Ptr Word8 -> Word8 -> IO (Ptr Word8)
step !Ptr Word8
p !Word8
w = do
        let ix :: Int
ix = Word8 -> Int
forall a b. (Integral a, Num b) => a -> b
fromIntegral Word8
w
        Ptr Word8 -> Word8 -> IO ()
forall a. Storable a => Ptr a -> a -> IO ()
poke   Ptr Word8
p     (ByteString -> Int -> Word8
BSU.unsafeIndex ByteString
hexDigits ((Int
ix Int -> Int -> Int
forall a. Bits a => a -> a -> a
.&. Int
0xF0) Int -> Int -> Int
forall a. Bits a => a -> Int -> a
`shiftR` Int
4))
        Ptr Word8 -> Word8 -> IO ()
forall a. Storable a => Ptr a -> a -> IO ()
poke   (Ptr Word8
p Ptr Word8 -> Int -> Ptr Word8
forall a b. Ptr a -> Int -> Ptr b
`plusPtr` Int
1) (ByteString -> Int -> Word8
BSU.unsafeIndex ByteString
hexDigits  (Int
ix Int -> Int -> Int
forall a. Bits a => a -> a -> a
.&. Int
0x0F))
        Ptr Word8 -> IO (Ptr Word8)
forall (m :: * -> *) a. Monad m => a -> m a
return (Ptr Word8
p Ptr Word8 -> Int -> Ptr Word8
forall a b. Ptr a -> Int -> Ptr b
`plusPtr` Int
2)

_asHexadecimal_overflow :: String
{-# NOINLINE _asHexadecimal_overflow #-}
_asHexadecimal_overflow :: String
_asHexadecimal_overflow =
    String
"asHexadecimal: cannot create buffer larger than (maxBound::Int)"


-- TODO: benchmark against the magichash hack used in Warp.
-- TODO(2021-10-23): Benchmark against the 'Addr#' hack that newer
--   Bytestring uses for hexadecimal stuff:
--   <https://github.com/haskell/bytestring/pull/418>
--
-- | The lower-case ASCII hexadecimal digits, in numerical order
-- for use as a lookup table.
hexDigits :: ByteString
{-# NOINLINE hexDigits #-}
hexDigits :: ByteString
hexDigits = String -> ByteString
BS8.pack String
"0123456789abcdef"


-- | We can only do this for MonadIO not just any Monad, but that's
-- good enough for what we need...
foldIO :: (a -> Word8 -> IO a) -> a -> ByteString -> IO a
{-# INLINE foldIO #-}
foldIO :: (a -> Word8 -> IO a) -> a -> ByteString -> IO a
foldIO a -> Word8 -> IO a
f a
z0 (BSI.PS ForeignPtr Word8
fp Int
off Int
len) =
    ForeignPtr Word8 -> (Ptr Word8 -> IO a) -> IO a
forall a b. ForeignPtr a -> (Ptr a -> IO b) -> IO b
FFI.withForeignPtr ForeignPtr Word8
fp ((Ptr Word8 -> IO a) -> IO a) -> (Ptr Word8 -> IO a) -> IO a
forall a b. (a -> b) -> a -> b
$ \Ptr Word8
p0 -> do
        let q :: Ptr b
q = Ptr Word8
p0 Ptr Word8 -> Int -> Ptr b
forall a b. Ptr a -> Int -> Ptr b
`plusPtr` (Int
offInt -> Int -> Int
forall a. Num a => a -> a -> a
+Int
len)
        let go :: a -> Ptr Word8 -> IO a
go !a
z !Ptr Word8
p
                | Ptr Word8
p Ptr Word8 -> Ptr Word8 -> Bool
forall a. Eq a => a -> a -> Bool
== Ptr Word8
forall b. Ptr b
q    = a -> IO a
forall (m :: * -> *) a. Monad m => a -> m a
return a
z
                | Bool
otherwise = do
                    Word8
w  <- Ptr Word8 -> IO Word8
forall a. Storable a => Ptr a -> IO a
peek Ptr Word8
p
                    a
z' <- a -> Word8 -> IO a
f a
z Word8
w
                    a -> Ptr Word8 -> IO a
go a
z' (Ptr Word8
p Ptr Word8 -> Int -> Ptr Word8
forall a b. Ptr a -> Int -> Ptr b
`plusPtr` Int
1)
        a -> Ptr Word8 -> IO a
go a
z0 (Ptr Word8
p0 Ptr Word8 -> Int -> Ptr Word8
forall a b. Ptr a -> Int -> Ptr b
`plusPtr` Int
off)


----------------------------------------------------------------
----------------------------------------------------------------
----- Octal

-- | Read a non-negative integral value in ASCII octal format.
-- Returns @Nothing@ if there is no integer at the beginning of the
-- string, otherwise returns @Just@ the integer read and the remainder
-- of the string.
--
-- This function does not recognize the various octal sigils like
-- \"0o\", but because there are different variants, those are best
-- handled by helper functions which then use this function for the
-- actual numerical parsing.
readOctal :: (Integral a) => ByteString -> Maybe (a, ByteString)
{-# SPECIALIZE readOctal ::
    ByteString -> Maybe (Int,     ByteString),
    ByteString -> Maybe (Int8,    ByteString),
    ByteString -> Maybe (Int16,   ByteString),
    ByteString -> Maybe (Int32,   ByteString),
    ByteString -> Maybe (Int64,   ByteString),
    ByteString -> Maybe (Integer, ByteString),
    ByteString -> Maybe (Word,    ByteString),
    ByteString -> Maybe (Word8,   ByteString),
    ByteString -> Maybe (Word16,  ByteString),
    ByteString -> Maybe (Word32,  ByteString),
    ByteString -> Maybe (Word64,  ByteString) #-}
readOctal :: ByteString -> Maybe (a, ByteString)
readOctal = ByteString -> Maybe (a, ByteString)
forall a. Num a => ByteString -> Maybe (a, ByteString)
start
    where
    start :: ByteString -> Maybe (t, ByteString)
start ByteString
xs
        | ByteString -> Bool
BS.null ByteString
xs = Maybe (t, ByteString)
forall a. Maybe a
Nothing
        | Bool
otherwise  =
            case ByteString -> Word8
BSU.unsafeHead ByteString
xs of
            Word8
w | Word8
0x37 Word8 -> Word8 -> Bool
forall a. Ord a => a -> a -> Bool
>= Word8
w Bool -> Bool -> Bool
&& Word8
w Word8 -> Word8 -> Bool
forall a. Ord a => a -> a -> Bool
>= Word8
0x30 ->
                    (t, ByteString) -> Maybe (t, ByteString)
forall a. a -> Maybe a
Just ((t, ByteString) -> Maybe (t, ByteString))
-> (t, ByteString) -> Maybe (t, ByteString)
forall a b. (a -> b) -> a -> b
$ t -> ByteString -> (t, ByteString)
forall a. Num a => a -> ByteString -> (a, ByteString)
loop (Word8 -> t
forall a b. (Integral a, Num b) => a -> b
fromIntegral (Word8
w Word8 -> Word8 -> Word8
forall a. Num a => a -> a -> a
- Word8
0x30)) (ByteString -> ByteString
BSU.unsafeTail ByteString
xs)
              | Bool
otherwise -> Maybe (t, ByteString)
forall a. Maybe a
Nothing

    loop :: t -> ByteString -> (t, ByteString)
loop !t
n !ByteString
xs
        | ByteString -> Bool
BS.null ByteString
xs = (t
n, ByteString
BS.empty) -- not @xs@, to help GC
        | Bool
otherwise  =
            case ByteString -> Word8
BSU.unsafeHead ByteString
xs of
            Word8
w | Word8
0x37 Word8 -> Word8 -> Bool
forall a. Ord a => a -> a -> Bool
>= Word8
w Bool -> Bool -> Bool
&& Word8
w Word8 -> Word8 -> Bool
forall a. Ord a => a -> a -> Bool
>= Word8
0x30 ->
                    t -> ByteString -> (t, ByteString)
loop (t
n t -> t -> t
forall a. Num a => a -> a -> a
* t
8 t -> t -> t
forall a. Num a => a -> a -> a
+ Word8 -> t
forall a b. (Integral a, Num b) => a -> b
fromIntegral (Word8
w Word8 -> Word8 -> Word8
forall a. Num a => a -> a -> a
- Word8
0x30)) (ByteString -> ByteString
BSU.unsafeTail ByteString
xs)
              | Bool
otherwise -> (t
n,ByteString
xs)


-- | Convert a non-negative integer into an ASCII octal string.
-- Returns @Nothing@ on negative inputs.
packOctal :: (Integral a) => a -> Maybe ByteString
{-# INLINE packOctal #-}
packOctal :: a -> Maybe ByteString
packOctal a
n
    | a
n a -> a -> Bool
forall a. Ord a => a -> a -> Bool
< a
0     = Maybe ByteString
forall a. Maybe a
Nothing
    | Bool
otherwise = ByteString -> Maybe ByteString
forall a. a -> Maybe a
Just (a -> ByteString
forall a. Integral a => a -> ByteString
unsafePackOctal a
n)


-- | Convert a non-negative integer into an ASCII octal string.
-- This function is unsafe to use on negative inputs.
unsafePackOctal :: (Integral a) => a -> ByteString
{-# SPECIALIZE unsafePackOctal ::
    Int     -> ByteString,
    Int8    -> ByteString,
    Int16   -> ByteString,
    Int32   -> ByteString,
    Int64   -> ByteString,
    Integer -> ByteString,
    Word    -> ByteString,
    Word8   -> ByteString,
    Word16  -> ByteString,
    Word32  -> ByteString,
    Word64  -> ByteString #-}
unsafePackOctal :: a -> ByteString
unsafePackOctal a
n0 =
    let size :: Int
size = Int -> Integer -> Int
forall a. (Integral a, Bits a) => Int -> a -> Int
numTwoPowerDigits Int
3 (a -> Integer
forall a. Integral a => a -> Integer
toInteger a
n0) -- for Bits
    in  Int -> (Ptr Word8 -> IO ()) -> ByteString
BSI.unsafeCreate Int
size ((Ptr Word8 -> IO ()) -> ByteString)
-> (Ptr Word8 -> IO ()) -> ByteString
forall a b. (a -> b) -> a -> b
$ \Ptr Word8
p0 ->
            a -> Ptr Word8 -> IO ()
forall a. Integral a => a -> Ptr Word8 -> IO ()
loop a
n0 (Ptr Word8
p0 Ptr Word8 -> Int -> Ptr Word8
forall a b. Ptr a -> Int -> Ptr b
`plusPtr` (Int
size Int -> Int -> Int
forall a. Num a => a -> a -> a
- Int
1))
    where
    loop :: (Integral a) => a -> Ptr Word8 -> IO ()
    loop :: a -> Ptr Word8 -> IO ()
loop a
n Ptr Word8
p
        | a
n a -> a -> Bool
forall a. Ord a => a -> a -> Bool
<= a
7    = do
            Ptr Word8 -> Word8 -> IO ()
forall a. Storable a => Ptr a -> a -> IO ()
poke Ptr Word8
p (Word8
0x30 Word8 -> Word8 -> Word8
forall a. Num a => a -> a -> a
+ a -> Word8
forall a b. (Integral a, Num b) => a -> b
fromIntegral a
n)
        | Bool
otherwise = do
            let (a
q,a
r) = a
n a -> a -> (a, a)
forall a. Integral a => a -> a -> (a, a)
`quotRem` a
8
            Ptr Word8 -> Word8 -> IO ()
forall a. Storable a => Ptr a -> a -> IO ()
poke Ptr Word8
p (Word8
0x30 Word8 -> Word8 -> Word8
forall a. Num a => a -> a -> a
+ a -> Word8
forall a b. (Integral a, Num b) => a -> b
fromIntegral a
r)
            a -> Ptr Word8 -> IO ()
forall a. Integral a => a -> Ptr Word8 -> IO ()
loop a
q (Ptr Word8
p Ptr Word8 -> Int -> Ptr Word8
forall a b. Ptr a -> Int -> Ptr b
`plusPtr` Int -> Int
forall a. Num a => a -> a
negate Int
1)

{-
-- BUG: This doesn't quite work right...
asOctal :: ByteString -> ByteString
asOctal buf =
    BSI.unsafeCreate (ceilEightThirds $ BS.length buf) $ \p0 -> do
        let (BSI.PS fq off len) = buf
        FFI.withForeignPtr fq $ \q0 -> do
            let qF = q0 `plusPtr` (off + len - rem len 3)
            let loop :: Ptr Word8 -> Ptr Word8 -> IO ()
                loop p q
                    | q /= qF   = do
                        {- Take three Word8s and write 8 chars at a time -}
                        i <- peek q
                        j <- peek (q `plusPtr` 1) :: IO Word8
                        k <- peek (q `plusPtr` 2) :: IO Word8
                        let w =     fromIntegral i
                                .|. (fromIntegral j `shiftL` 8)
                                .|. (fromIntegral k `shiftL` 16)
                        poke p               (toC8( w              .&. 0x07))
                        poke (p `plusPtr` 1) (toC8((w `shiftR`  3) .&. 0x07))
                        poke (p `plusPtr` 2) (toC8((w `shiftR`  6) .&. 0x07))
                        poke (p `plusPtr` 3) (toC8((w `shiftR`  9) .&. 0x07))
                        poke (p `plusPtr` 4) (toC8((w `shiftR` 12) .&. 0x07))
                        poke (p `plusPtr` 5) (toC8((w `shiftR` 15) .&. 0x07))
                        poke (p `plusPtr` 6) (toC8((w `shiftR` 18) .&. 0x07))
                        poke (p `plusPtr` 7) (toC8((w `shiftR` 21) .&. 0x07))
                        loop (p `plusPtr` 8) (q `plusPtr` 3)
                    | 2 == rem len 3 = do
                        {- Handle the last two Word8s -}
                        i <- peek q
                        j <- peek (q `plusPtr` 1) :: IO Word8
                        let w =      fromIntegral i
                                .|. (fromIntegral j `shiftL` 8)
                        poke p               (toC8( w              .&. 0x07))
                        poke (p `plusPtr` 1) (toC8((w `shiftR`  3) .&. 0x07))
                        poke (p `plusPtr` 2) (toC8((w `shiftR`  6) .&. 0x07))
                        poke (p `plusPtr` 3) (toC8((w `shiftR`  9) .&. 0x07))
                        poke (p `plusPtr` 4) (toC8((w `shiftR` 12) .&. 0x07))
                        poke (p `plusPtr` 5) (toC8((w `shiftR` 15) .&. 0x01))
                    | otherwise = do
                        {- Handle the last Word8 -}
                        i <- peek q
                        let w = fromIntegral i
                        poke p               (toC8( w              .&. 0x07))
                        poke (p `plusPtr` 1) (toC8((w `shiftR`  3) .&. 0x07))
                        poke (p `plusPtr` 2) (toC8((w `shiftR`  6) .&. 0x03))
            --
            loop p0 (q0 `plusPtr` off)
    where
    toC8 :: Int -> Word8
    toC8 i = fromIntegral (0x30+i)
    {-# INLINE toC8 #-}
    -- We can probably speed that up by using (.|.) in lieu of (+)

    -- See the benchmark file for credits and implementation details.
    ceilEightThirds x
        | x >= 3*(b-1) = error _asOctal_overflow
        | x >= b       = ceiling (fromIntegral x / 3 * 8 :: Double)
        | otherwise    = (x*8 + 2) `quot` 3
        where
        {-# INLINE b #-}
        b = 2^(28::Int)::Int -- b*8-1 is the last positive number for Int=Int32
        -- TODO: need to generalize for Int=Int64

_asOctal_overflow :: String
{-# NOINLINE _asOctal_overflow #-}
_asOctal_overflow =
    "asOctal: cannot create buffer larger than (maxBound::Int)"
-- -}

----------------------------------------------------------------
----------------------------------------------------------- fin.