{-# language BangPatterns #-}
{-# language DataKinds #-}
{-# language GADTSyntax #-}
{-# language LambdaCase #-}
{-# language MagicHash #-}
{-# language RankNTypes #-}
{-# language ScopedTypeVariables #-}
{-# language TypeApplications #-}
{-# language UnboxedTuples #-}

-- | This module provides functions for encoding fixed-width words
-- using the base-62 encoding scheme. The encoding functions in this
-- module produce byte sequences that are ASCII-compatible text
-- encodings (e.g. ISO-8859-1 and UTF-8). Similarly, the decoding
-- functions only decode byte sequences that are an ASCII-compatible
-- text encoding of characters in the class @[A-Za-Z0-9]@. Other
-- encodings (notably UTF-16) are not supported but would be
-- accepted in a pull request.
module Data.Word.Base62
  ( -- * 64-bit Word
    encode64
  , builder64
  , decode64
    -- * 128-bit Word
  , encode128
  , builder128
  , decode128
  ) where

import Data.Bytes.Builder.Bounded.Unsafe (Builder(..))
import Data.Bytes.Types (Bytes(Bytes))
import Data.Char (ord)
import Data.Primitive (ByteArray(..),readByteArray,writeByteArray)
import Data.Primitive (MutableByteArray(MutableByteArray))
import Data.WideWord.Word128 (Word128(Word128))
import GHC.Exts (Char(C#),quotRemWord#,indexCharArray#)
import GHC.Exts (ByteArray#,Int#,Int(I#),Word#,(+#),(-#),writeWord8Array#)
import GHC.Exts (isTrue#,(>#))
import GHC.ST (ST(ST))
import GHC.Word (Word64(W64#),Word8(W8#),Word(W#))

import qualified Arithmetic.Nat as Nat
import qualified Data.Bytes as Bytes
import qualified Data.Bytes.Builder.Bounded as Builder
import qualified GHC.Exts as Exts

-- $setup
-- >>> :set -XNumericUnderscores
-- >>> import qualified Data.Bytes as Bytes

-- | Base62 encode a 64-bit word. Leading zero bits are suppressed.
--
-- >>> putStrLn (Bytes.toLatinString (Bytes.fromByteArray (encode64 213635)))
-- tZj
--
-- Note that this will encode the number 0 as the character 0 rather
-- than as the empty byte array.
encode64 :: Word64 -> ByteArray
encode64 :: Word64 -> ByteArray
encode64 = Nat 11 -> Builder 11 -> ByteArray
forall (n :: Nat). Nat n -> Builder n -> ByteArray
Builder.run Nat 11
forall (n :: Nat). KnownNat n => Nat n
Nat.constant (Builder 11 -> ByteArray)
-> (Word64 -> Builder 11) -> Word64 -> ByteArray
forall b c a. (b -> c) -> (a -> b) -> a -> c
. Word64 -> Builder 11
builder64

-- | Base62 encode a 64-bit word as a builder.
builder64 :: Word64 -> Builder 11
{-# inline builder64 #-}
builder64 :: Word64 -> Builder 11
builder64 (W64# Word#
w) = Word# -> Builder 11
builder64# Word#
w

-- | Base62 encode a 128-bit word. Leading zero bits are suppressed.
--
-- >>> let octillion = 1_000_000_000_000_000_000_000_000_000
-- >>> putStrLn (Bytes.toLatinString (Bytes.fromByteArray (encode128 octillion)))
-- 1IdHllabYuAOlNK4
encode128 :: Word128 -> ByteArray
encode128 :: Word128 -> ByteArray
encode128 = Nat 22 -> Builder 22 -> ByteArray
forall (n :: Nat). Nat n -> Builder n -> ByteArray
Builder.run Nat 22
forall (n :: Nat). KnownNat n => Nat n
Nat.constant (Builder 22 -> ByteArray)
-> (Word128 -> Builder 22) -> Word128 -> ByteArray
forall b c a. (b -> c) -> (a -> b) -> a -> c
. Word128 -> Builder 22
builder128

-- | Base62 encode a 128-bit word as a builder.
builder128 :: Word128 -> Builder 22
{-# inline builder128 #-}
builder128 :: Word128 -> Builder 22
builder128 (Word128 (W64# Word#
a) (W64# Word#
b)) = Word# -> Word# -> Builder 22
builder128# Word#
a Word#
b

builder64# :: Word# -> Builder 11
{-# noinline builder64# #-}
builder64# :: Word# -> Builder 11
builder64# Word#
w0 = (forall s.
 MutableByteArray# s -> Int# -> State# s -> (# State# s, Int# #))
-> Builder 11
forall (a :: Nat).
(forall s.
 MutableByteArray# s -> Int# -> State# s -> (# State# s, Int# #))
-> Builder a
Builder
  (\MutableByteArray# s
marr Int#
off0 State# s
s0 -> case Word#
w0 of
    Word#
0## -> case MutableByteArray# s -> Int# -> Word# -> State# s -> State# s
forall d.
MutableByteArray# d -> Int# -> Word# -> State# d -> State# d
writeWord8Array# MutableByteArray# s
marr Int#
off0 Word#
48## State# s
s0 of
      State# s
s1 -> (# State# s
s1, Int#
off0 Int# -> Int# -> Int#
+# Int#
1# #)
    Word#
_ -> let go :: Int# -> Word# -> State# s -> (# State# s, Int# #)
go Int#
ix Word#
w State# s
s1 = case Word#
w of
               Word#
0## -> case MutableByteArray s -> Int -> Int -> ST s ()
forall s. MutableByteArray s -> Int -> Int -> ST s ()
reverseBytes (MutableByteArray# s -> MutableByteArray s
forall s. MutableByteArray# s -> MutableByteArray s
MutableByteArray MutableByteArray# s
marr) (Int# -> Int
I# Int#
off0) (Int# -> Int
I# (Int#
ix Int# -> Int# -> Int#
-# Int#
1# )) of
                 ST STRep s ()
f -> case STRep s ()
f State# s
s1 of
                   (# State# s
s2, (()
_ :: ()) #) -> (# State# s
s2, Int#
ix #)
               Word#
_ ->
                 let !(# Word#
q, Word#
r #) = Word# -> Word# -> (# Word#, Word# #)
quotRemWord# Word#
w Word#
62##
                  in case MutableByteArray# s -> Int# -> Word# -> State# s -> State# s
forall d.
MutableByteArray# d -> Int# -> Word# -> State# d -> State# d
writeWord8Array# MutableByteArray# s
marr Int#
ix (Word8 -> Word#
unW8 (Word -> Word8
encodeByte (Word# -> Word
W# Word#
r))) State# s
s1 of
                       State# s
s2 -> Int# -> Word# -> State# s -> (# State# s, Int# #)
go (Int#
ix Int# -> Int# -> Int#
+# Int#
1#) Word#
q State# s
s2
          in Int# -> Word# -> State# s -> (# State# s, Int# #)
go Int#
off0 Word#
w0 State# s
s0
  )

-- Always outputs exactly ten digits. They do not need to be reversed.
builder62pow10# :: Word# -> Builder 10
{-# noinline builder62pow10# #-}
builder62pow10# :: Word# -> Builder 10
builder62pow10# Word#
w0 = (forall s.
 MutableByteArray# s -> Int# -> State# s -> (# State# s, Int# #))
-> Builder 10
forall (a :: Nat).
(forall s.
 MutableByteArray# s -> Int# -> State# s -> (# State# s, Int# #))
-> Builder a
Builder
  (\MutableByteArray# s
marr Int#
off0 State# s
s0 -> 
    let go :: Int# -> Int# -> Word# -> State# s -> (# State# s, Int# #)
go Int#
ix Int#
d Word#
w State# s
s1 = case Int#
d of
          Int#
0# -> (# State# s
s1, Int#
ix Int# -> Int# -> Int#
+# Int#
11# #) 
          Int#
_ ->
            let !(# Word#
q, Word#
r #) = Word# -> Word# -> (# Word#, Word# #)
quotRemWord# Word#
w Word#
62##
             in case MutableByteArray# s -> Int# -> Word# -> State# s -> State# s
forall d.
MutableByteArray# d -> Int# -> Word# -> State# d -> State# d
writeWord8Array# MutableByteArray# s
marr Int#
ix (Word8 -> Word#
unW8 (Word -> Word8
encodeByte (Word# -> Word
W# Word#
r))) State# s
s1 of
                  State# s
s2 -> Int# -> Int# -> Word# -> State# s -> (# State# s, Int# #)
go (Int#
ix Int# -> Int# -> Int#
-# Int#
1# ) (Int#
d Int# -> Int# -> Int#
-# Int#
1# ) Word#
q State# s
s2
     in Int# -> Int# -> Word# -> State# s -> (# State# s, Int# #)
go (Int#
off0 Int# -> Int# -> Int#
+# Int#
9# ) Int#
10# Word#
w0 State# s
s0
  )

builder128# :: Word# -> Word# -> Builder 22
{-# noinline builder128# #-}
builder128# :: Word# -> Word# -> Builder 22
builder128# Word#
wa Word#
wb = (forall s.
 MutableByteArray# s -> Int# -> State# s -> (# State# s, Int# #))
-> Builder 22
forall (a :: Nat).
(forall s.
 MutableByteArray# s -> Int# -> State# s -> (# State# s, Int# #))
-> Builder a
Builder
  (\MutableByteArray# s
marr Int#
off0 State# s
s0 -> case Word#
wa of
    Word#
0## -> case Word# -> Builder 11
builder64# Word#
wb of Builder forall s.
MutableByteArray# s -> Int# -> State# s -> (# State# s, Int# #)
f -> MutableByteArray# s -> Int# -> State# s -> (# State# s, Int# #)
forall s.
MutableByteArray# s -> Int# -> State# s -> (# State# s, Int# #)
f MutableByteArray# s
marr Int#
off0 State# s
s0
    Word#
_ -> case Word128 -> Word128 -> (Word128, Word128)
forall a. Integral a => a -> a -> (a, a)
quotRem (Word64 -> Word64 -> Word128
Word128 (Word# -> Word64
W64# Word#
wa) (Word# -> Word64
W64# Word#
wb)) (Word64 -> Word64 -> Word128
Word128 Word64
0 Word64
n62pow10) of
      (upper :: Word128
upper@(Word128 Word64
upperHi (W64# Word#
upperLo)), (Word128 Word64
shouldBeZeroA (W64# Word#
lower))) -> case Word64
shouldBeZeroA of
        Word64
0 -> case Word64
upperHi of
          Word64
0 -> case Word# -> Builder 11
builder64# Word#
upperLo Builder 11 -> Builder 10 -> Builder (11 + 10)
forall (m :: Nat) (n :: Nat).
Builder m -> Builder n -> Builder (m + n)
`Builder.append` Word# -> Builder 10
builder62pow10# Word#
lower of Builder forall s.
MutableByteArray# s -> Int# -> State# s -> (# State# s, Int# #)
f -> MutableByteArray# s -> Int# -> State# s -> (# State# s, Int# #)
forall s.
MutableByteArray# s -> Int# -> State# s -> (# State# s, Int# #)
f MutableByteArray# s
marr Int#
off0 State# s
s0
          Word64
_ -> case Word128 -> Word128 -> (Word128, Word128)
forall a. Integral a => a -> a -> (a, a)
quotRem Word128
upper (Word64 -> Word64 -> Word128
Word128 Word64
0 Word64
n62pow10) of
            (Word128 Word64
shouldBeZeroB (W64# Word#
x),Word128 Word64
shouldBeZeroC (W64# Word#
y)) -> case Word64
shouldBeZeroB of
              Word64
0 -> case Word64
shouldBeZeroC of
                Word64
0 -> case Word# -> Builder 11
builder64# Word#
x Builder 11 -> Builder 20 -> Builder (11 + 20)
forall (m :: Nat) (n :: Nat).
Builder m -> Builder n -> Builder (m + n)
`Builder.append` (Word# -> Builder 10
builder62pow10# Word#
y Builder 10 -> Builder 10 -> Builder (10 + 10)
forall (m :: Nat) (n :: Nat).
Builder m -> Builder n -> Builder (m + n)
`Builder.append` Word# -> Builder 10
builder62pow10# Word#
lower) of Builder forall s.
MutableByteArray# s -> Int# -> State# s -> (# State# s, Int# #)
f -> MutableByteArray# s -> Int# -> State# s -> (# State# s, Int# #)
forall s.
MutableByteArray# s -> Int# -> State# s -> (# State# s, Int# #)
f MutableByteArray# s
marr Int#
off0 State# s
s0
                Word64
_ -> [Char] -> (# State# s, Int# #)
forall a. HasCallStack => [Char] -> a
error [Char]
"Data.Word.Base62: logical error c"
              Word64
_ -> [Char] -> (# State# s, Int# #)
forall a. HasCallStack => [Char] -> a
error [Char]
"Data.Word.Base62: logical error b"
        Word64
_ -> [Char] -> (# State# s, Int# #)
forall a. HasCallStack => [Char] -> a
error [Char]
"Data.Word.Base62: logical error a"
  )

-- Reverse the bytes in the designated slice. This takes
-- an inclusive start offset and an inclusive end offset.
reverseBytes :: MutableByteArray s -> Int -> Int -> ST s ()
{-# inline reverseBytes #-}
reverseBytes :: MutableByteArray s -> Int -> Int -> ST s ()
reverseBytes MutableByteArray s
arr Int
begin Int
end = Int -> Int -> ST s ()
go Int
begin Int
end where
  go :: Int -> Int -> ST s ()
go Int
ixA Int
ixB = if Int
ixA Int -> Int -> Bool
forall a. Ord a => a -> a -> Bool
< Int
ixB
    then do
      Word8
a :: Word8 <- MutableByteArray (PrimState (ST s)) -> Int -> ST s Word8
forall a (m :: * -> *).
(Prim a, PrimMonad m) =>
MutableByteArray (PrimState m) -> Int -> m a
readByteArray MutableByteArray s
MutableByteArray (PrimState (ST s))
arr Int
ixA
      Word8
b :: Word8 <- MutableByteArray (PrimState (ST s)) -> Int -> ST s Word8
forall a (m :: * -> *).
(Prim a, PrimMonad m) =>
MutableByteArray (PrimState m) -> Int -> m a
readByteArray MutableByteArray s
MutableByteArray (PrimState (ST s))
arr Int
ixB
      MutableByteArray (PrimState (ST s)) -> Int -> Word8 -> ST s ()
forall a (m :: * -> *).
(Prim a, PrimMonad m) =>
MutableByteArray (PrimState m) -> Int -> a -> m ()
writeByteArray MutableByteArray s
MutableByteArray (PrimState (ST s))
arr Int
ixA Word8
b
      MutableByteArray (PrimState (ST s)) -> Int -> Word8 -> ST s ()
forall a (m :: * -> *).
(Prim a, PrimMonad m) =>
MutableByteArray (PrimState m) -> Int -> a -> m ()
writeByteArray MutableByteArray s
MutableByteArray (PrimState (ST s))
arr Int
ixB Word8
a
      Int -> Int -> ST s ()
go (Int
ixA Int -> Int -> Int
forall a. Num a => a -> a -> a
+ Int
1) (Int
ixB Int -> Int -> Int
forall a. Num a => a -> a -> a
- Int
1)
    else () -> ST s ()
forall (f :: * -> *) a. Applicative f => a -> f a
pure ()

-- Precondition: argument is less than 62.
encodeByte :: Word -> Word8
encodeByte :: Word -> Word8
encodeByte Word
w
  | Word
w Word -> Word -> Bool
forall a. Ord a => a -> a -> Bool
< Word
10 = Word -> Word8
unsafeW8 (Char -> Word
c2w Char
'0' Word -> Word -> Word
forall a. Num a => a -> a -> a
+ Word
w)
  | Word
w Word -> Word -> Bool
forall a. Ord a => a -> a -> Bool
< Word
36 = Word -> Word8
unsafeW8 ((Char -> Word
c2w Char
'A' Word -> Word -> Word
forall a. Num a => a -> a -> a
- Word
10) Word -> Word -> Word
forall a. Num a => a -> a -> a
+ Word
w)
  | Bool
otherwise = Word -> Word8
unsafeW8 ((Char -> Word
c2w Char
'a' Word -> Word -> Word
forall a. Num a => a -> a -> a
- Word
36) Word -> Word -> Word
forall a. Num a => a -> a -> a
+ Word
w)

-- We use Char here since it produces more readable Core.
-- Performance is not impacted in any way.
decodeByte :: Char -> Maybe Word
decodeByte :: Char -> Maybe Word
decodeByte Char
w
  | Char
w Char -> Char -> Bool
forall a. Ord a => a -> a -> Bool
>= Char
'0' Bool -> Bool -> Bool
&& Char
w Char -> Char -> Bool
forall a. Ord a => a -> a -> Bool
<= Char
'9' = Word -> Maybe Word
forall a. a -> Maybe a
Just (Char -> Word
c2w Char
w Word -> Word -> Word
forall a. Num a => a -> a -> a
- Char -> Word
c2w Char
'0')
  | Char
w Char -> Char -> Bool
forall a. Ord a => a -> a -> Bool
>= Char
'A' Bool -> Bool -> Bool
&& Char
w Char -> Char -> Bool
forall a. Ord a => a -> a -> Bool
<= Char
'Z' = Word -> Maybe Word
forall a. a -> Maybe a
Just (Char -> Word
c2w Char
w Word -> Word -> Word
forall a. Num a => a -> a -> a
- (Char -> Word
c2w Char
'A' Word -> Word -> Word
forall a. Num a => a -> a -> a
- Word
10))
  | Char
w Char -> Char -> Bool
forall a. Ord a => a -> a -> Bool
>= Char
'a' Bool -> Bool -> Bool
&& Char
w Char -> Char -> Bool
forall a. Ord a => a -> a -> Bool
<= Char
'z' = Word -> Maybe Word
forall a. a -> Maybe a
Just (Char -> Word
c2w Char
w Word -> Word -> Word
forall a. Num a => a -> a -> a
- (Char -> Word
c2w Char
'a' Word -> Word -> Word
forall a. Num a => a -> a -> a
- Word
36))
  | Bool
otherwise = Maybe Word
forall a. Maybe a
Nothing

c2w :: Char -> Word
c2w :: Char -> Word
c2w = Int -> Word
forall a b. (Integral a, Num b) => a -> b
fromIntegral (Int -> Word) -> (Char -> Int) -> Char -> Word
forall b c a. (b -> c) -> (a -> b) -> a -> c
. Char -> Int
ord

-- Precondition: the argument is less than 256
unsafeW8 :: Word -> Word8
unsafeW8 :: Word -> Word8
unsafeW8 (W# Word#
w) = Word# -> Word8
W8# Word#
w

unW8 :: Word8 -> Word#
unW8 :: Word8 -> Word#
unW8 (W8# Word#
w) = Word#
w

unW :: Word -> Word#
unW :: Word -> Word#
unW (W# Word#
w) = Word#
w

-- | Decode a base62-encoded 64-bit word. This rejects the empty
-- string rather than decoding it as zero. This also rejects encoded
-- numbers greater than or equal to @2^64@.
--
-- >>> decode64 (Bytes.fromAsciiString "LygHa16AHYB")
-- Just 18446744073709551611
-- >>> decode64 (Bytes.fromAsciiString "1IdHllabYuAOlNK4")
-- Nothing
decode64 :: Bytes -> Maybe Word64
{-# inline decode64 #-}
decode64 :: Bytes -> Maybe Word64
decode64 b :: Bytes
b@(Bytes ByteArray
_ Int
_ Int
len) = case Int
len of
  Int
0 -> Maybe Word64
forall a. Maybe a
Nothing
  Int
_ -> case Word -> Bytes -> (# (# #) | Word# #)
decode64# Word
0 Bytes
b of
    (# (# #) | #) -> Maybe Word64
forall a. Maybe a
Nothing
    (# | Word#
w #) -> Word64 -> Maybe Word64
forall a. a -> Maybe a
Just (Word# -> Word64
W64# Word#
w)

-- Worker-wrapper will turn this into good code as long as
-- we do not put a noinline pragma on it. It is recursive,
-- so it cannot inline anywhere.
decode64# :: Word -> Bytes -> (# (# #) | Word# #)
decode64# :: Word -> Bytes -> (# (# #) | Word# #)
decode64# !Word
acc b :: Bytes
b@(Bytes ByteArray
arr Int
off Int
len) = case Int
len of
  Int
0 -> (# | Word -> Word#
unW Word
acc #)
  Int
_ -> case Char -> Maybe Word
decodeByte (ByteArray -> Int -> Char
indexAsciiArray ByteArray
arr Int
off) of
    Maybe Word
Nothing -> (# (# #) | #)
    Just Word
w ->
      -- If we overflow, the accumulator will shrink. We
      -- return Nothing in this case.
      let (Bool
overflow,Word
acc') = Word -> Word -> (Bool, Word)
unsignedPushBase62 Word
acc Word
w
       in if Bool
overflow
            then (# (# #) | #)
            else Word -> Bytes -> (# (# #) | Word# #)
decode64# Word
acc' (Int -> Bytes -> Bytes
Bytes.unsafeDrop Int
1 Bytes
b)

n62pow10 :: Word64
n62pow10 :: Word64
n62pow10 = Word64
62 Word64 -> Word64 -> Word64
forall a. Num a => a -> a -> a
* Word64
62 Word64 -> Word64 -> Word64
forall a. Num a => a -> a -> a
* Word64
62 Word64 -> Word64 -> Word64
forall a. Num a => a -> a -> a
* Word64
62 Word64 -> Word64 -> Word64
forall a. Num a => a -> a -> a
* Word64
62 Word64 -> Word64 -> Word64
forall a. Num a => a -> a -> a
* Word64
62 Word64 -> Word64 -> Word64
forall a. Num a => a -> a -> a
* Word64
62 Word64 -> Word64 -> Word64
forall a. Num a => a -> a -> a
* Word64
62 Word64 -> Word64 -> Word64
forall a. Num a => a -> a -> a
* Word64
62 Word64 -> Word64 -> Word64
forall a. Num a => a -> a -> a
* Word64
62

n62pow20 :: Word128
n62pow20 :: Word128
n62pow20 = Word64 -> Word64 -> Word128
Word128 Word64
0 Word64
n62pow10 Word128 -> Word128 -> Word128
forall a. Num a => a -> a -> a
* Word64 -> Word64 -> Word128
Word128 Word64
0 Word64
n62pow10

-- Precondition: there are at least 10 bytes starting at the offset.
-- The result is in [0,62^10) Notice that we do not need to check
-- for overflow in this function. While @off@ tracks the actual
-- position in the bytearray, @d@ tracks the number of digits
-- consumed by this particular function. The caller should always
-- set @d@ to 0.
unsafeDecode62pow10# :: Word -> ByteArray -> Int -> Int -> (# (# #) | Word# #)
unsafeDecode62pow10# :: Word -> ByteArray -> Int -> Int -> (# (# #) | Word# #)
unsafeDecode62pow10# !Word
acc !ByteArray
arr !Int
off !Int
d = if Int
d Int -> Int -> Bool
forall a. Ord a => a -> a -> Bool
< Int
10
  then case Char -> Maybe Word
decodeByte (ByteArray -> Int -> Char
indexAsciiArray ByteArray
arr Int
off) of
    Maybe Word
Nothing -> (# (# #) | #)
    Just Word
w ->
      let acc' :: Word
acc' = Word
acc Word -> Word -> Word
forall a. Num a => a -> a -> a
* Word
62 Word -> Word -> Word
forall a. Num a => a -> a -> a
+ Word
w
       in Word -> ByteArray -> Int -> Int -> (# (# #) | Word# #)
unsafeDecode62pow10# Word
acc' ByteArray
arr (Int
off Int -> Int -> Int
forall a. Num a => a -> a -> a
+ Int
1) (Int
d Int -> Int -> Int
forall a. Num a => a -> a -> a
+ Int
1)
  else (# | Word -> Word#
unW Word
acc #)

-- | Decode a base62-encoded 128-bit word. This rejects the empty
-- string rather than decoding it as zero. This also rejects encoded
-- numbers greater than or equal to @2^128@.
--
-- >>> decode128 (Bytes.fromAsciiString "LygHa16AHYB")
-- Just 18446744073709551611
-- >>> decode128 (Bytes.fromAsciiString "7n42DGM5Tflk9n8mt7Fhc6")
-- Just 340282366920938463463374607431768211454
-- >>> decode128 (Bytes.fromAsciiString "7n42DGM5Tflk9n8mt7Fhc9")
-- Nothing
decode128 :: Bytes -> Maybe Word128
{-# inline decode128 #-}
decode128 :: Bytes -> Maybe Word128
decode128 (Bytes (ByteArray ByteArray#
arr) (I# Int#
off) (I# Int#
len)) =
  case ByteArray# -> Int# -> Int# -> (# (# #) | (# Word#, Word# #) #)
decode128# ByteArray#
arr Int#
off Int#
len of
    (# (# #) | #) -> Maybe Word128
forall a. Maybe a
Nothing
    (# | (# Word#
a, Word#
b #) #) -> Word128 -> Maybe Word128
forall a. a -> Maybe a
Just (Word64 -> Word64 -> Word128
Word128 (Word# -> Word64
W64# Word#
a) (Word# -> Word64
W64# Word#
b))

decode128# :: ByteArray# -> Int# -> Int# -> (# (# #) | (# Word#, Word# #) #)
{-# noinline decode128# #-}
decode128# :: ByteArray# -> Int# -> Int# -> (# (# #) | (# Word#, Word# #) #)
decode128# ByteArray#
arr Int#
off Int#
len
  | Int# -> Bool
isTrue# (Int#
len Int# -> Int# -> Int#
># Int#
22# ) = (# (# #) | #) -- always overflows
  | Int# -> Bool
isTrue# (Int#
len Int# -> Int# -> Int#
># Int#
20# ) =
      case Word -> ByteArray -> Int -> Int -> (# (# #) | Word# #)
unsafeDecode62pow10# Word
0 (ByteArray# -> ByteArray
ByteArray ByteArray#
arr) (Int# -> Int
I# (Int#
off Int# -> Int# -> Int#
+# Int#
len Int# -> Int# -> Int#
-# Int#
10# )) Int
0 of
        (# (# #) | #) -> (# (# #) | #)
        (# | Word#
c #) -> case Word -> ByteArray -> Int -> Int -> (# (# #) | Word# #)
unsafeDecode62pow10# Word
0 (ByteArray# -> ByteArray
ByteArray ByteArray#
arr) (Int# -> Int
I# (Int#
off Int# -> Int# -> Int#
+# Int#
len Int# -> Int# -> Int#
-# Int#
20# )) Int
0 of
          (# (# #) | #) -> (# (# #) | #)
          (# | Word#
b #) -> case Word -> Bytes -> (# (# #) | Word# #)
decode64# Word
0 (ByteArray -> Int -> Int -> Bytes
Bytes (ByteArray# -> ByteArray
ByteArray ByteArray#
arr) (Int# -> Int
I# Int#
off) (Int# -> Int
I# (Int#
len Int# -> Int# -> Int#
-# Int#
20# ))) of
            (# (# #) | #) -> (# (# #) | #)
            (# | Word#
a #) -> if Word# -> Word64
W64# Word#
a Word64 -> Word64 -> Bool
forall a. Ord a => a -> a -> Bool
< Word64
484
              then
                let r0 :: Word128
r0 = Word64 -> Word64 -> Word128
Word128 Word64
0 (Word# -> Word64
W64# Word#
c) Word128 -> Word128 -> Word128
forall a. Num a => a -> a -> a
+ (Word64 -> Word64 -> Word128
Word128 Word64
0 Word64
n62pow10 Word128 -> Word128 -> Word128
forall a. Num a => a -> a -> a
* (Word64 -> Word64 -> Word128
Word128 Word64
0 (Word# -> Word64
W64# Word#
b)))
                    !r1 :: Word128
r1@(Word128 (W64# Word#
r1x) (W64# Word#
r1y)) = Word128
n62pow20 Word128 -> Word128 -> Word128
forall a. Num a => a -> a -> a
* Word64 -> Word64 -> Word128
Word128 Word64
0 (Word# -> Word64
W64# Word#
a) Word128 -> Word128 -> Word128
forall a. Num a => a -> a -> a
+ Word128
r0
                 in if Word128
r1 Word128 -> Word128 -> Bool
forall a. Ord a => a -> a -> Bool
>= Word128
r0
                      then (# | (# Word#
r1x, Word#
r1y #) #)
                      else (# (# #) | #)
              else (# (# #) | #)
  | Int# -> Bool
isTrue# (Int#
len Int# -> Int# -> Int#
># Int#
10# ) =
      case Word -> ByteArray -> Int -> Int -> (# (# #) | Word# #)
unsafeDecode62pow10# Word
0 (ByteArray# -> ByteArray
ByteArray ByteArray#
arr) (Int# -> Int
I# (Int#
off Int# -> Int# -> Int#
+# Int#
len Int# -> Int# -> Int#
-# Int#
10# )) Int
0 of
        (# (# #) | #) -> (# (# #) | #)
        (# | Word#
b #) -> case Word -> Bytes -> (# (# #) | Word# #)
decode64# Word
0 (ByteArray -> Int -> Int -> Bytes
Bytes (ByteArray# -> ByteArray
ByteArray ByteArray#
arr) (Int# -> Int
I# Int#
off) (Int# -> Int
I# (Int#
len Int# -> Int# -> Int#
-# Int#
10# ))) of
          (# (# #) | #) -> (# (# #) | #)
          (# | Word#
a #) -> case Word64 -> Word64 -> Word128
Word128 Word64
0 (Word# -> Word64
W64# Word#
b) Word128 -> Word128 -> Word128
forall a. Num a => a -> a -> a
+ (Word64 -> Word128
forall a b. (Integral a, Num b) => a -> b
fromIntegral Word64
n62pow10 Word128 -> Word128 -> Word128
forall a. Num a => a -> a -> a
* Word64 -> Word64 -> Word128
Word128 Word64
0 (Word# -> Word64
W64# Word#
a)) of
            Word128 (W64# Word#
x) (W64# Word#
y) -> (# | (# Word#
x, Word#
y #) #)
  | Bool
otherwise = case Word -> Bytes -> (# (# #) | Word# #)
decode64# Word
0 (ByteArray -> Int -> Int -> Bytes
Bytes (ByteArray# -> ByteArray
ByteArray ByteArray#
arr) (Int# -> Int
I# Int#
off) (Int# -> Int
I# Int#
len)) of
      (# (# #) | #) -> (# (# #) | #)
      (# | Word#
w #) -> (# | (# Word#
0##, Word#
w #) #)

indexAsciiArray :: ByteArray -> Int -> Char
indexAsciiArray :: ByteArray -> Int -> Char
indexAsciiArray (ByteArray ByteArray#
arr) (I# Int#
i) = Char# -> Char
C# (ByteArray# -> Int# -> Char#
indexCharArray# ByteArray#
arr Int#
i)

unsignedPushBase62 :: Word -> Word -> (Bool,Word)
unsignedPushBase62 :: Word -> Word -> (Bool, Word)
unsignedPushBase62 (W# Word#
a) (W# Word#
b) = 
  let !(# Word#
ca, Word#
r0 #) = Word# -> Word# -> (# Word#, Word# #)
Exts.timesWord2# Word#
a Word#
62##
      !r1 :: Word#
r1 = Word# -> Word# -> Word#
Exts.plusWord# Word#
r0 Word#
b
      !cb :: Word#
cb = Int# -> Word#
Exts.int2Word# (Word# -> Word# -> Int#
Exts.ltWord# Word#
r1 Word#
r0)
      !c :: Word#
c = Word#
ca Word# -> Word# -> Word#
`Exts.or#` Word#
cb
   in (case Word#
c of { Word#
0## -> Bool
False; Word#
_ -> Bool
True }, Word# -> Word
W# Word#
r1)