-- |
-- Module      : Basement.String
-- License     : BSD-style
-- Maintainer  : Vincent Hanquez <vincent@snarc.org>
-- Stability   : experimental
-- Portability : portable
--
-- A String type backed by a UTF8 encoded byte array and all the necessary
-- functions to manipulate the string.
--
-- You can think of String as a specialization of a byte array that
-- have element of type Char.
--
-- The String data must contain UTF8 valid data.
--
{-# LANGUAGE BangPatterns               #-}
{-# LANGUAGE MagicHash                  #-}
{-# LANGUAGE NoImplicitPrelude          #-}
{-# LANGUAGE TypeFamilies               #-}
{-# LANGUAGE UnboxedTuples              #-}
{-# LANGUAGE FlexibleContexts           #-}
{-# LANGUAGE CPP                        #-}
module Basement.String
    ( String(..)
    , MutableString(..)
    , create
    , replicate
    , length
    -- * Binary conversion
    , Encoding(..)
    , fromBytes
    , fromChunkBytes
    , fromBytesUnsafe
    , fromBytesLenient
    , toBytes
    , mutableValidate
    , copy
    , ValidationFailure(..)
    , index
    , null
    , drop
    , take
    , splitAt
    , revDrop
    , revTake
    , revSplitAt
    , splitOn
    , sub
    , elem
    , indices
    , intersperse
    , span
    , spanEnd
    , break
    , breakEnd
    , breakElem
    , breakLine
    , dropWhile
    , singleton
    , charMap
    , snoc
    , cons
    , unsnoc
    , uncons
    , find
    , findIndex
    , sortBy
    , filter
    , reverse
    , replace
    , builderAppend
    , builderBuild
    , builderBuild_
    , readInteger
    , readIntegral
    , readNatural
    , readDouble
    , readRational
    , readFloatingExact
    , upper
    , lower
    , caseFold
    , isPrefixOf
    , isSuffixOf
    , isInfixOf
    , stripPrefix
    , stripSuffix
    , all
    , any
    -- * Legacy utility
    , lines
    , words
    , toBase64
    , toBase64URL
    , toBase64OpenBSD
    ) where

import           Basement.UArray           (UArray)
import qualified Basement.UArray           as Vec
import qualified Basement.UArray           as C
import qualified Basement.UArray.Mutable   as MVec
import           Basement.Block.Mutable (Block(..), MutableBlock(..))
import qualified Basement.Block.Mutable    as MBLK
import           Basement.Compat.Bifunctor
import           Basement.Compat.Base
import           Basement.Compat.Natural
import           Basement.Compat.MonadTrans
import           Basement.Compat.Primitive
import           Basement.Types.OffsetSize
import           Basement.Numerical.Additive
import           Basement.Numerical.Subtractive
import           Basement.Numerical.Multiplicative
import           Basement.Numerical.Number
import           Basement.Cast
import           Basement.Monad
import           Basement.PrimType
import           Basement.FinalPtr
import           Basement.IntegralConv
import           Basement.Floating
import           Basement.MutableBuilder
import           Basement.String.CaseMapping (upperMapping, lowerMapping, foldMapping)
import           Basement.UTF8.Table
import           Basement.UTF8.Helper
import           Basement.UTF8.Base
import           Basement.UTF8.Types
import           Basement.UArray.Base as C (onBackendPrim, onBackend, onBackendPure, offset, ValidRange(..), offsetsValidRange, MUArray(..), MUArrayBackend(..))
import           Basement.Alg.Class (Indexable)
import qualified Basement.Alg.UTF8 as UTF8
import qualified Basement.Alg.String as Alg
import           Basement.Types.Char7 (Char7(..), c7Upper, c7Lower)
import qualified Basement.Types.Char7 as Char7
import           GHC.Prim
import           GHC.ST
import           GHC.Types
import           GHC.Word
#if MIN_VERSION_base(4,9,0)
import           GHC.Char
#endif

 -- temporary
import qualified Data.List
import           Data.Ratio
import           Data.Char (toUpper, toLower)
import qualified Prelude

import qualified Basement.String.Encoding.Encoding   as Encoder
import qualified Basement.String.Encoding.ASCII7     as Encoder
import qualified Basement.String.Encoding.UTF16      as Encoder
import qualified Basement.String.Encoding.UTF32      as Encoder
import qualified Basement.String.Encoding.ISO_8859_1 as Encoder

-- | UTF8 Encoder
data EncoderUTF8 = EncoderUTF8

instance Encoder.Encoding EncoderUTF8 where
    type Unit EncoderUTF8 = Word8
    type Error EncoderUTF8 = ValidationFailure
    encodingNext :: EncoderUTF8
-> (Offset (Unit EncoderUTF8) -> Unit EncoderUTF8)
-> Offset (Unit EncoderUTF8)
-> Either (Error EncoderUTF8) (Char, Offset (Unit EncoderUTF8))
encodingNext  EncoderUTF8
_ = \Offset (Unit EncoderUTF8) -> Unit EncoderUTF8
ofs -> (Char, Offset Word8)
-> Either ValidationFailure (Char, Offset Word8)
forall a b. b -> Either a b
Right ((Char, Offset Word8)
 -> Either ValidationFailure (Char, Offset Word8))
-> (Offset Word8 -> (Char, Offset Word8))
-> Offset Word8
-> Either ValidationFailure (Char, Offset Word8)
forall k (cat :: k -> k -> *) (b :: k) (c :: k) (a :: k).
Category cat =>
cat b c -> cat a b -> cat a c
. (Offset Word8 -> Word8) -> Offset Word8 -> (Char, Offset Word8)
nextWithIndexer Offset Word8 -> Word8
Offset (Unit EncoderUTF8) -> Unit EncoderUTF8
ofs
    encodingWrite :: EncoderUTF8
-> Char
-> Builder
     (UArray (Unit EncoderUTF8))
     (MUArray (Unit EncoderUTF8))
     (Unit EncoderUTF8)
     st
     err
     ()
encodingWrite EncoderUTF8
_ = Char
-> Builder
     (UArray (Unit EncoderUTF8))
     (MUArray (Unit EncoderUTF8))
     (Unit EncoderUTF8)
     st
     err
     ()
forall (st :: * -> *) err.
(PrimMonad st, Monad st) =>
Char -> Builder (UArray Word8) (MUArray Word8) Word8 st err ()
writeWithBuilder

-- | Validate a bytearray for UTF8'ness
--
-- On success Nothing is returned
-- On Failure the position along with the failure reason
validate :: UArray Word8
         -> Offset8
         -> CountOf Word8
         -> (Offset8, Maybe ValidationFailure)
validate :: UArray Word8
-> Offset Word8
-> CountOf Word8
-> (Offset Word8, Maybe ValidationFailure)
validate UArray Word8
array Offset Word8
ofsStart CountOf Word8
sz = (Block Word8
 -> Offset Word8 -> (Offset Word8, Maybe ValidationFailure))
-> (Ptr Word8
    -> Offset Word8 -> ST Any (Offset Word8, Maybe ValidationFailure))
-> UArray Word8
-> (Offset Word8, Maybe ValidationFailure)
forall ty a s.
(Block ty -> Offset ty -> a)
-> (Ptr ty -> Offset ty -> ST s a) -> UArray ty -> a
C.unsafeDewrap Block Word8
-> Offset Word8 -> (Offset Word8, Maybe ValidationFailure)
goBa Ptr Word8
-> Offset Word8 -> ST Any (Offset Word8, Maybe ValidationFailure)
goAddr UArray Word8
array
  where
    unTranslateOffset :: Offset a -> p (Offset a) c -> p (Offset a) c
unTranslateOffset Offset a
start = (Offset a -> Offset a) -> p (Offset a) c -> p (Offset a) c
forall (p :: * -> * -> *) a b c.
Bifunctor p =>
(a -> b) -> p a c -> p b c
first (\Offset a
e -> Offset a
e Offset a -> Offset a -> Offset a
forall a. Offset a -> Offset a -> Offset a
`offsetSub` Offset a
start)
    goBa :: Block Word8
-> Offset Word8 -> (Offset Word8, Maybe ValidationFailure)
goBa Block Word8
ba Offset Word8
start =
        Offset Word8
-> (Offset Word8, Maybe ValidationFailure)
-> (Offset Word8, Maybe ValidationFailure)
forall (p :: * -> * -> *) a c.
Bifunctor p =>
Offset a -> p (Offset a) c -> p (Offset a) c
unTranslateOffset Offset Word8
start ((Offset Word8, Maybe ValidationFailure)
 -> (Offset Word8, Maybe ValidationFailure))
-> (Offset Word8, Maybe ValidationFailure)
-> (Offset Word8, Maybe ValidationFailure)
forall a b. (a -> b) -> a -> b
$ Offset Word8
-> Block Word8
-> Offset Word8
-> (Offset Word8, Maybe ValidationFailure)
forall container.
Indexable container Word8 =>
Offset Word8
-> container
-> Offset Word8
-> (Offset Word8, Maybe ValidationFailure)
Alg.validate (Offset Word8
startOffset Word8 -> Offset Word8 -> Offset Word8
forall a. Additive a => a -> a -> a
+Offset Word8
end) Block Word8
ba (Offset Word8
start Offset Word8 -> Offset Word8 -> Offset Word8
forall a. Additive a => a -> a -> a
+ Offset Word8
ofsStart)
    goAddr :: Ptr Word8
-> Offset Word8 -> ST Any (Offset Word8, Maybe ValidationFailure)
goAddr ptr :: Ptr Word8
ptr@(Ptr !Addr#
_) Offset Word8
start =
        (Offset Word8, Maybe ValidationFailure)
-> ST Any (Offset Word8, Maybe ValidationFailure)
forall (f :: * -> *) a. Applicative f => a -> f a
pure ((Offset Word8, Maybe ValidationFailure)
 -> ST Any (Offset Word8, Maybe ValidationFailure))
-> (Offset Word8, Maybe ValidationFailure)
-> ST Any (Offset Word8, Maybe ValidationFailure)
forall a b. (a -> b) -> a -> b
$ Offset Word8
-> (Offset Word8, Maybe ValidationFailure)
-> (Offset Word8, Maybe ValidationFailure)
forall (p :: * -> * -> *) a c.
Bifunctor p =>
Offset a -> p (Offset a) c -> p (Offset a) c
unTranslateOffset Offset Word8
start ((Offset Word8, Maybe ValidationFailure)
 -> (Offset Word8, Maybe ValidationFailure))
-> (Offset Word8, Maybe ValidationFailure)
-> (Offset Word8, Maybe ValidationFailure)
forall a b. (a -> b) -> a -> b
$ Offset Word8
-> Ptr Word8
-> Offset Word8
-> (Offset Word8, Maybe ValidationFailure)
forall container.
Indexable container Word8 =>
Offset Word8
-> container
-> Offset Word8
-> (Offset Word8, Maybe ValidationFailure)
Alg.validate (Offset Word8
startOffset Word8 -> Offset Word8 -> Offset Word8
forall a. Additive a => a -> a -> a
+Offset Word8
end) Ptr Word8
ptr (Offset Word8
ofsStart Offset Word8 -> Offset Word8 -> Offset Word8
forall a. Additive a => a -> a -> a
+ Offset Word8
start)
    end :: Offset Word8
end = Offset Word8
ofsStart Offset Word8 -> CountOf Word8 -> Offset Word8
forall ty. Offset ty -> CountOf ty -> Offset ty
`offsetPlusE` CountOf Word8
sz

-- | Similar to 'validate' but works on a 'MutableByteArray'
mutableValidate :: PrimMonad prim
                => MVec.MUArray Word8 (PrimState prim)
                -> Offset Word8
                -> CountOf Word8
                -> prim (Offset Word8, Maybe ValidationFailure)
mutableValidate :: MUArray Word8 (PrimState prim)
-> Offset Word8
-> CountOf Word8
-> prim (Offset Word8, Maybe ValidationFailure)
mutableValidate MUArray Word8 (PrimState prim)
mba Offset Word8
ofsStart CountOf Word8
sz = do
    Offset Word8 -> prim (Offset Word8, Maybe ValidationFailure)
loop Offset Word8
ofsStart
  where
    end :: Offset Word8
end = Offset Word8
ofsStart Offset Word8 -> CountOf Word8 -> Offset Word8
forall ty. Offset ty -> CountOf ty -> Offset ty
`offsetPlusE` CountOf Word8
sz

    loop :: Offset Word8 -> prim (Offset Word8, Maybe ValidationFailure)
loop Offset Word8
ofs
        | Offset Word8
ofs Offset Word8 -> Offset Word8 -> Bool
forall a. Ord a => a -> a -> Bool
> Offset Word8
end  = [Char] -> prim (Offset Word8, Maybe ValidationFailure)
forall a. HasCallStack => [Char] -> a
error [Char]
"mutableValidate: internal error: went pass offset"
        | Offset Word8
ofs Offset Word8 -> Offset Word8 -> Bool
forall a. Eq a => a -> a -> Bool
== Offset Word8
end = (Offset Word8, Maybe ValidationFailure)
-> prim (Offset Word8, Maybe ValidationFailure)
forall (m :: * -> *) a. Monad m => a -> m a
return (Offset Word8
end, Maybe ValidationFailure
forall a. Maybe a
Nothing)
        | Bool
otherwise  = do
            (Offset Word8, Maybe ValidationFailure)
r <- Offset Word8 -> prim (Offset Word8, Maybe ValidationFailure)
one Offset Word8
ofs
            case (Offset Word8, Maybe ValidationFailure)
r of
                (Offset Word8
nextOfs, Maybe ValidationFailure
Nothing)  -> Offset Word8 -> prim (Offset Word8, Maybe ValidationFailure)
loop Offset Word8
nextOfs
                (Offset Word8
pos, Just ValidationFailure
failure) -> (Offset Word8, Maybe ValidationFailure)
-> prim (Offset Word8, Maybe ValidationFailure)
forall (m :: * -> *) a. Monad m => a -> m a
return (Offset Word8
pos, ValidationFailure -> Maybe ValidationFailure
forall a. a -> Maybe a
Just ValidationFailure
failure)

    one :: Offset Word8 -> prim (Offset Word8, Maybe ValidationFailure)
one Offset Word8
pos = do
        StepASCII
h <- Word8 -> StepASCII
StepASCII (Word8 -> StepASCII) -> prim Word8 -> prim StepASCII
forall (f :: * -> *) a b. Functor f => (a -> b) -> f a -> f b
<$> MUArray Word8 (PrimState prim) -> Offset Word8 -> prim Word8
forall (prim :: * -> *) ty.
(PrimMonad prim, PrimType ty) =>
MUArray ty (PrimState prim) -> Offset ty -> prim ty
Vec.unsafeRead MUArray Word8 (PrimState prim)
mba Offset Word8
pos
        let nbConts :: Int
nbConts = StepASCII -> Int
getNbBytes StepASCII
h
        if Int
nbConts Int -> Int -> Bool
forall a. Eq a => a -> a -> Bool
== Int
0xff
            then (Offset Word8, Maybe ValidationFailure)
-> prim (Offset Word8, Maybe ValidationFailure)
forall (m :: * -> *) a. Monad m => a -> m a
return (Offset Word8
pos, ValidationFailure -> Maybe ValidationFailure
forall a. a -> Maybe a
Just ValidationFailure
InvalidHeader)
            else if Offset Word8
pos Offset Word8 -> Offset Word8 -> Offset Word8
forall a. Additive a => a -> a -> a
+ Offset Word8
1 Offset Word8 -> Offset Word8 -> Offset Word8
forall a. Additive a => a -> a -> a
+ Int -> Offset Word8
forall ty. Int -> Offset ty
Offset Int
nbConts Offset Word8 -> Offset Word8 -> Bool
forall a. Ord a => a -> a -> Bool
> Offset Word8
end
                then (Offset Word8, Maybe ValidationFailure)
-> prim (Offset Word8, Maybe ValidationFailure)
forall (m :: * -> *) a. Monad m => a -> m a
return (Offset Word8
pos, ValidationFailure -> Maybe ValidationFailure
forall a. a -> Maybe a
Just ValidationFailure
MissingByte)
                else do
                    case Int
nbConts of
                        Int
0 -> (Offset Word8, Maybe ValidationFailure)
-> prim (Offset Word8, Maybe ValidationFailure)
forall (m :: * -> *) a. Monad m => a -> m a
return (Offset Word8
pos Offset Word8 -> Offset Word8 -> Offset Word8
forall a. Additive a => a -> a -> a
+ Offset Word8
1, Maybe ValidationFailure
forall a. Maybe a
Nothing)
                        Int
1 -> do
                            Word8
c1 <- MUArray Word8 (PrimState prim) -> Offset Word8 -> prim Word8
forall (prim :: * -> *) ty.
(PrimMonad prim, PrimType ty) =>
MUArray ty (PrimState prim) -> Offset ty -> prim ty
Vec.unsafeRead MUArray Word8 (PrimState prim)
mba (Offset Word8
pos Offset Word8 -> Offset Word8 -> Offset Word8
forall a. Additive a => a -> a -> a
+ Offset Word8
1)
                            if Word8 -> Bool
isContinuation Word8
c1
                                then (Offset Word8, Maybe ValidationFailure)
-> prim (Offset Word8, Maybe ValidationFailure)
forall (m :: * -> *) a. Monad m => a -> m a
return (Offset Word8
pos Offset Word8 -> Offset Word8 -> Offset Word8
forall a. Additive a => a -> a -> a
+ Offset Word8
2, Maybe ValidationFailure
forall a. Maybe a
Nothing)
                                else (Offset Word8, Maybe ValidationFailure)
-> prim (Offset Word8, Maybe ValidationFailure)
forall (m :: * -> *) a. Monad m => a -> m a
return (Offset Word8
pos, ValidationFailure -> Maybe ValidationFailure
forall a. a -> Maybe a
Just ValidationFailure
InvalidContinuation)
                        Int
2 -> do
                            Word8
c1 <- MUArray Word8 (PrimState prim) -> Offset Word8 -> prim Word8
forall (prim :: * -> *) ty.
(PrimMonad prim, PrimType ty) =>
MUArray ty (PrimState prim) -> Offset ty -> prim ty
Vec.unsafeRead MUArray Word8 (PrimState prim)
mba (Offset Word8
pos Offset Word8 -> Offset Word8 -> Offset Word8
forall a. Additive a => a -> a -> a
+ Offset Word8
1)
                            Word8
c2 <- MUArray Word8 (PrimState prim) -> Offset Word8 -> prim Word8
forall (prim :: * -> *) ty.
(PrimMonad prim, PrimType ty) =>
MUArray ty (PrimState prim) -> Offset ty -> prim ty
Vec.unsafeRead MUArray Word8 (PrimState prim)
mba (Offset Word8
pos Offset Word8 -> Offset Word8 -> Offset Word8
forall a. Additive a => a -> a -> a
+ Offset Word8
2)
                            if Word8 -> Bool
isContinuation Word8
c1 Bool -> Bool -> Bool
&& Word8 -> Bool
isContinuation Word8
c2
                                then (Offset Word8, Maybe ValidationFailure)
-> prim (Offset Word8, Maybe ValidationFailure)
forall (m :: * -> *) a. Monad m => a -> m a
return (Offset Word8
pos Offset Word8 -> Offset Word8 -> Offset Word8
forall a. Additive a => a -> a -> a
+ Offset Word8
3, Maybe ValidationFailure
forall a. Maybe a
Nothing)
                                else (Offset Word8, Maybe ValidationFailure)
-> prim (Offset Word8, Maybe ValidationFailure)
forall (m :: * -> *) a. Monad m => a -> m a
return (Offset Word8
pos, ValidationFailure -> Maybe ValidationFailure
forall a. a -> Maybe a
Just ValidationFailure
InvalidContinuation)
                        Int
3 -> do
                            Word8
c1 <- MUArray Word8 (PrimState prim) -> Offset Word8 -> prim Word8
forall (prim :: * -> *) ty.
(PrimMonad prim, PrimType ty) =>
MUArray ty (PrimState prim) -> Offset ty -> prim ty
Vec.unsafeRead MUArray Word8 (PrimState prim)
mba (Offset Word8
pos Offset Word8 -> Offset Word8 -> Offset Word8
forall a. Additive a => a -> a -> a
+ Offset Word8
1)
                            Word8
c2 <- MUArray Word8 (PrimState prim) -> Offset Word8 -> prim Word8
forall (prim :: * -> *) ty.
(PrimMonad prim, PrimType ty) =>
MUArray ty (PrimState prim) -> Offset ty -> prim ty
Vec.unsafeRead MUArray Word8 (PrimState prim)
mba (Offset Word8
pos Offset Word8 -> Offset Word8 -> Offset Word8
forall a. Additive a => a -> a -> a
+ Offset Word8
2)
                            Word8
c3 <- MUArray Word8 (PrimState prim) -> Offset Word8 -> prim Word8
forall (prim :: * -> *) ty.
(PrimMonad prim, PrimType ty) =>
MUArray ty (PrimState prim) -> Offset ty -> prim ty
Vec.unsafeRead MUArray Word8 (PrimState prim)
mba (Offset Word8
pos Offset Word8 -> Offset Word8 -> Offset Word8
forall a. Additive a => a -> a -> a
+ Offset Word8
3)
                            if Word8 -> Bool
isContinuation Word8
c1 Bool -> Bool -> Bool
&& Word8 -> Bool
isContinuation Word8
c2 Bool -> Bool -> Bool
&& Word8 -> Bool
isContinuation Word8
c3
                                then (Offset Word8, Maybe ValidationFailure)
-> prim (Offset Word8, Maybe ValidationFailure)
forall (m :: * -> *) a. Monad m => a -> m a
return (Offset Word8
pos Offset Word8 -> Offset Word8 -> Offset Word8
forall a. Additive a => a -> a -> a
+ Offset Word8
4, Maybe ValidationFailure
forall a. Maybe a
Nothing)
                                else (Offset Word8, Maybe ValidationFailure)
-> prim (Offset Word8, Maybe ValidationFailure)
forall (m :: * -> *) a. Monad m => a -> m a
return (Offset Word8
pos, ValidationFailure -> Maybe ValidationFailure
forall a. a -> Maybe a
Just ValidationFailure
InvalidContinuation)
                        Int
_ -> [Char] -> prim (Offset Word8, Maybe ValidationFailure)
forall a. HasCallStack => [Char] -> a
error [Char]
"internal error"

nextWithIndexer :: (Offset Word8 -> Word8)
                -> Offset Word8
                -> (Char, Offset Word8)
nextWithIndexer :: (Offset Word8 -> Word8) -> Offset Word8 -> (Char, Offset Word8)
nextWithIndexer Offset Word8 -> Word8
getter Offset Word8
off =
    case Word8# -> Int#
getNbBytes# Word8#
b# of
        Int#
0# -> (Word8# -> Char
toChar Word8#
h, Offset Word8
off Offset Word8 -> Offset Word8 -> Offset Word8
forall a. Additive a => a -> a -> a
+ Offset Word8
1)
        Int#
1# -> (Word8# -> Char
toChar (Word8 -> Word8#
decode2 (Offset Word8 -> Word8
getter (Offset Word8 -> Word8) -> Offset Word8 -> Word8
forall a b. (a -> b) -> a -> b
$ Offset Word8
off Offset Word8 -> Offset Word8 -> Offset Word8
forall a. Additive a => a -> a -> a
+ Offset Word8
1)), Offset Word8
off Offset Word8 -> Offset Word8 -> Offset Word8
forall a. Additive a => a -> a -> a
+ Offset Word8
2)
        Int#
2# -> (Word8# -> Char
toChar (Word8 -> Word8 -> Word8#
decode3 (Offset Word8 -> Word8
getter (Offset Word8 -> Word8) -> Offset Word8 -> Word8
forall a b. (a -> b) -> a -> b
$ Offset Word8
off Offset Word8 -> Offset Word8 -> Offset Word8
forall a. Additive a => a -> a -> a
+ Offset Word8
1) (Offset Word8 -> Word8
getter (Offset Word8 -> Word8) -> Offset Word8 -> Word8
forall a b. (a -> b) -> a -> b
$ Offset Word8
off Offset Word8 -> Offset Word8 -> Offset Word8
forall a. Additive a => a -> a -> a
+ Offset Word8
2)), Offset Word8
off Offset Word8 -> Offset Word8 -> Offset Word8
forall a. Additive a => a -> a -> a
+ Offset Word8
3)
        Int#
3# -> (Word8# -> Char
toChar (Word8 -> Word8 -> Word8 -> Word8#
decode4 (Offset Word8 -> Word8
getter (Offset Word8 -> Word8) -> Offset Word8 -> Word8
forall a b. (a -> b) -> a -> b
$ Offset Word8
off Offset Word8 -> Offset Word8 -> Offset Word8
forall a. Additive a => a -> a -> a
+ Offset Word8
1) (Offset Word8 -> Word8
getter (Offset Word8 -> Word8) -> Offset Word8 -> Word8
forall a b. (a -> b) -> a -> b
$ Offset Word8
off Offset Word8 -> Offset Word8 -> Offset Word8
forall a. Additive a => a -> a -> a
+ Offset Word8
2) (Offset Word8 -> Word8
getter (Offset Word8 -> Word8) -> Offset Word8 -> Word8
forall a b. (a -> b) -> a -> b
$ Offset Word8
off Offset Word8 -> Offset Word8 -> Offset Word8
forall a. Additive a => a -> a -> a
+ Offset Word8
3))
              , Offset Word8
off Offset Word8 -> Offset Word8 -> Offset Word8
forall a. Additive a => a -> a -> a
+ Offset Word8
4)
        Int#
r -> [Char] -> (Char, Offset Word8)
forall a. HasCallStack => [Char] -> a
error ([Char]
"next: internal error: invalid input: " [Char] -> [Char] -> [Char]
forall a. Semigroup a => a -> a -> a
<> Int -> [Char]
forall a. Show a => a -> [Char]
show (Int# -> Int
I# Int#
r) [Char] -> [Char] -> [Char]
forall a. Semigroup a => a -> a -> a
<> [Char]
" " [Char] -> [Char] -> [Char]
forall a. Semigroup a => a -> a -> a
<> Word -> [Char]
forall a. Show a => a -> [Char]
show (Word8# -> Word
W# Word8#
h))
  where
    b :: Word8
b@(W8# Word8#
b#) = Offset Word8 -> Word8
getter Offset Word8
off
    !(W# Word8#
h) = Word8 -> Word
forall a b. IntegralUpsize a b => a -> b
integralUpsize Word8
b

    toChar :: Word# -> Char
    toChar :: Word8# -> Char
toChar Word8#
w = Char# -> Char
C# (Int# -> Char#
chr# (Word8# -> Int#
word2Int# Word8#
w))

    decode2 :: Word8 -> Word#
    decode2 :: Word8 -> Word8#
decode2 (W8# Word8#
b1) =
        Word8# -> Word8# -> Word8#
or# (Word8# -> Int# -> Word8#
uncheckedShiftL# (Word8# -> Word8# -> Word8#
and# Word8#
h Word8#
0x1f##) Int#
6#)
            (Word8# -> Word8# -> Word8#
and# Word8#
c1 Word8#
0x3f##)
      where
        c1 :: Word8#
c1 = Word8# -> Word8#
word8ToWord# Word8#
b1

    decode3 :: Word8 -> Word8 -> Word#
    decode3 :: Word8 -> Word8 -> Word8#
decode3 (W8# Word8#
b1) (W8# Word8#
b2) =
        Word8# -> Word8# -> Word8#
or# (Word8# -> Int# -> Word8#
uncheckedShiftL# (Word8# -> Word8# -> Word8#
and# Word8#
h Word8#
0xf##) Int#
12#)
            (Word8# -> Word8# -> Word8#
or# (Word8# -> Int# -> Word8#
uncheckedShiftL# (Word8# -> Word8# -> Word8#
and# Word8#
c1 Word8#
0x3f##) Int#
6#)
                 (Word8# -> Word8# -> Word8#
and# Word8#
c2 Word8#
0x3f##))
      where
        c1 :: Word8#
c1 = Word8# -> Word8#
word8ToWord# Word8#
b1
        c2 :: Word8#
c2 = Word8# -> Word8#
word8ToWord# Word8#
b2

    decode4 :: Word8 -> Word8 -> Word8 -> Word#
    decode4 :: Word8 -> Word8 -> Word8 -> Word8#
decode4 (W8# Word8#
b1) (W8# Word8#
b2) (W8# Word8#
b3) =
        Word8# -> Word8# -> Word8#
or# (Word8# -> Int# -> Word8#
uncheckedShiftL# (Word8# -> Word8# -> Word8#
and# Word8#
h Word8#
0x7##) Int#
18#)
            (Word8# -> Word8# -> Word8#
or# (Word8# -> Int# -> Word8#
uncheckedShiftL# (Word8# -> Word8# -> Word8#
and# Word8#
c1 Word8#
0x3f##) Int#
12#)
                (Word8# -> Word8# -> Word8#
or# (Word8# -> Int# -> Word8#
uncheckedShiftL# (Word8# -> Word8# -> Word8#
and# Word8#
c2 Word8#
0x3f##) Int#
6#)
                    (Word8# -> Word8# -> Word8#
and# Word8#
c3 Word8#
0x3f##))
            )
      where
        c1 :: Word8#
c1 = Word8# -> Word8#
word8ToWord# Word8#
b1
        c2 :: Word8#
c2 = Word8# -> Word8#
word8ToWord# Word8#
b2
        c3 :: Word8#
c3 = Word8# -> Word8#
word8ToWord# Word8#
b3

writeWithBuilder :: (PrimMonad st, Monad st)
                 => Char
                 -> Builder (UArray Word8) (MVec.MUArray Word8) Word8 st err ()
writeWithBuilder :: Char -> Builder (UArray Word8) (MUArray Word8) Word8 st err ()
writeWithBuilder Char
c
    | Int# -> Bool
bool# (Word8# -> Word8# -> Int#
ltWord# Word8#
x Word8#
0x80##   ) = Builder (UArray Word8) (MUArray Word8) Word8 st err ()
encode1
    | Int# -> Bool
bool# (Word8# -> Word8# -> Int#
ltWord# Word8#
x Word8#
0x800##  ) = Builder (UArray Word8) (MUArray Word8) Word8 st err ()
encode2
    | Int# -> Bool
bool# (Word8# -> Word8# -> Int#
ltWord# Word8#
x Word8#
0x10000##) = Builder (UArray Word8) (MUArray Word8) Word8 st err ()
encode3
    | Bool
otherwise = Builder (UArray Word8) (MUArray Word8) Word8 st err ()
encode4
  where
    !(I# Int#
xi) = Char -> Int
forall a. Enum a => a -> Int
fromEnum Char
c
    !x :: Word8#
x       = Int# -> Word8#
int2Word# Int#
xi

    encode1 :: Builder (UArray Word8) (MUArray Word8) Word8 st err ()
encode1 = Word8 -> Builder (UArray Word8) (MUArray Word8) Word8 st err ()
forall ty (state :: * -> *) err.
(PrimType ty, PrimMonad state) =>
ty -> Builder (UArray ty) (MUArray ty) ty state err ()
Vec.builderAppend (Word8# -> Word8
W8# (Word8# -> Word8#
wordToWord8# Word8#
x))

    encode2 :: Builder (UArray Word8) (MUArray Word8) Word8 st err ()
encode2 = do
        let x1 :: Word8#
x1  = Word8# -> Word8# -> Word8#
or# (Word8# -> Int# -> Word8#
uncheckedShiftRL# Word8#
x Int#
6#) Word8#
0xc0##
            x2 :: Word8#
x2  = Word8# -> Word8#
toContinuation Word8#
x
        Word8 -> Builder (UArray Word8) (MUArray Word8) Word8 st err ()
forall ty (state :: * -> *) err.
(PrimType ty, PrimMonad state) =>
ty -> Builder (UArray ty) (MUArray ty) ty state err ()
Vec.builderAppend (Word8# -> Word8
W8# (Word8# -> Word8#
wordToWord8# Word8#
x1)) Builder (UArray Word8) (MUArray Word8) Word8 st err ()
-> Builder (UArray Word8) (MUArray Word8) Word8 st err ()
-> Builder (UArray Word8) (MUArray Word8) Word8 st err ()
forall (m :: * -> *) a b. Monad m => m a -> m b -> m b
>> Word8 -> Builder (UArray Word8) (MUArray Word8) Word8 st err ()
forall ty (state :: * -> *) err.
(PrimType ty, PrimMonad state) =>
ty -> Builder (UArray ty) (MUArray ty) ty state err ()
Vec.builderAppend (Word8# -> Word8
W8# (Word8# -> Word8#
wordToWord8# Word8#
x2))

    encode3 :: Builder (UArray Word8) (MUArray Word8) Word8 st err ()
encode3 = do
        let x1 :: Word8#
x1  = Word8# -> Word8# -> Word8#
or# (Word8# -> Int# -> Word8#
uncheckedShiftRL# Word8#
x Int#
12#) Word8#
0xe0##
            x2 :: Word8#
x2  = Word8# -> Word8#
toContinuation (Word8# -> Int# -> Word8#
uncheckedShiftRL# Word8#
x Int#
6#)
            x3 :: Word8#
x3  = Word8# -> Word8#
toContinuation Word8#
x
        Word8 -> Builder (UArray Word8) (MUArray Word8) Word8 st err ()
forall ty (state :: * -> *) err.
(PrimType ty, PrimMonad state) =>
ty -> Builder (UArray ty) (MUArray ty) ty state err ()
Vec.builderAppend (Word8# -> Word8
W8# (Word8# -> Word8#
wordToWord8# Word8#
x1)) Builder (UArray Word8) (MUArray Word8) Word8 st err ()
-> Builder (UArray Word8) (MUArray Word8) Word8 st err ()
-> Builder (UArray Word8) (MUArray Word8) Word8 st err ()
forall (m :: * -> *) a b. Monad m => m a -> m b -> m b
>> Word8 -> Builder (UArray Word8) (MUArray Word8) Word8 st err ()
forall ty (state :: * -> *) err.
(PrimType ty, PrimMonad state) =>
ty -> Builder (UArray ty) (MUArray ty) ty state err ()
Vec.builderAppend (Word8# -> Word8
W8# (Word8# -> Word8#
wordToWord8# Word8#
x2)) Builder (UArray Word8) (MUArray Word8) Word8 st err ()
-> Builder (UArray Word8) (MUArray Word8) Word8 st err ()
-> Builder (UArray Word8) (MUArray Word8) Word8 st err ()
forall (m :: * -> *) a b. Monad m => m a -> m b -> m b
>> Word8 -> Builder (UArray Word8) (MUArray Word8) Word8 st err ()
forall ty (state :: * -> *) err.
(PrimType ty, PrimMonad state) =>
ty -> Builder (UArray ty) (MUArray ty) ty state err ()
Vec.builderAppend (Word8# -> Word8
W8# (Word8# -> Word8#
wordToWord8# Word8#
x3))

    encode4 :: Builder (UArray Word8) (MUArray Word8) Word8 st err ()
encode4 = do
        let x1 :: Word8#
x1  = Word8# -> Word8# -> Word8#
or# (Word8# -> Int# -> Word8#
uncheckedShiftRL# Word8#
x Int#
18#) Word8#
0xf0##
            x2 :: Word8#
x2  = Word8# -> Word8#
toContinuation (Word8# -> Int# -> Word8#
uncheckedShiftRL# Word8#
x Int#
12#)
            x3 :: Word8#
x3  = Word8# -> Word8#
toContinuation (Word8# -> Int# -> Word8#
uncheckedShiftRL# Word8#
x Int#
6#)
            x4 :: Word8#
x4  = Word8# -> Word8#
toContinuation Word8#
x
        Word8 -> Builder (UArray Word8) (MUArray Word8) Word8 st err ()
forall ty (state :: * -> *) err.
(PrimType ty, PrimMonad state) =>
ty -> Builder (UArray ty) (MUArray ty) ty state err ()
Vec.builderAppend (Word8# -> Word8
W8# (Word8# -> Word8#
wordToWord8# Word8#
x1)) Builder (UArray Word8) (MUArray Word8) Word8 st err ()
-> Builder (UArray Word8) (MUArray Word8) Word8 st err ()
-> Builder (UArray Word8) (MUArray Word8) Word8 st err ()
forall (m :: * -> *) a b. Monad m => m a -> m b -> m b
>> Word8 -> Builder (UArray Word8) (MUArray Word8) Word8 st err ()
forall ty (state :: * -> *) err.
(PrimType ty, PrimMonad state) =>
ty -> Builder (UArray ty) (MUArray ty) ty state err ()
Vec.builderAppend (Word8# -> Word8
W8# (Word8# -> Word8#
wordToWord8# Word8#
x2)) Builder (UArray Word8) (MUArray Word8) Word8 st err ()
-> Builder (UArray Word8) (MUArray Word8) Word8 st err ()
-> Builder (UArray Word8) (MUArray Word8) Word8 st err ()
forall (m :: * -> *) a b. Monad m => m a -> m b -> m b
>> Word8 -> Builder (UArray Word8) (MUArray Word8) Word8 st err ()
forall ty (state :: * -> *) err.
(PrimType ty, PrimMonad state) =>
ty -> Builder (UArray ty) (MUArray ty) ty state err ()
Vec.builderAppend (Word8# -> Word8
W8# (Word8# -> Word8#
wordToWord8# Word8#
x3)) Builder (UArray Word8) (MUArray Word8) Word8 st err ()
-> Builder (UArray Word8) (MUArray Word8) Word8 st err ()
-> Builder (UArray Word8) (MUArray Word8) Word8 st err ()
forall (m :: * -> *) a b. Monad m => m a -> m b -> m b
>> Word8 -> Builder (UArray Word8) (MUArray Word8) Word8 st err ()
forall ty (state :: * -> *) err.
(PrimType ty, PrimMonad state) =>
ty -> Builder (UArray ty) (MUArray ty) ty state err ()
Vec.builderAppend (Word8# -> Word8
W8# (Word8# -> Word8#
wordToWord8# Word8#
x4))

    toContinuation :: Word# -> Word#
    toContinuation :: Word8# -> Word8#
toContinuation Word8#
w = Word8# -> Word8# -> Word8#
or# (Word8# -> Word8# -> Word8#
and# Word8#
w Word8#
0x3f##) Word8#
0x80##

writeUTF8Char :: PrimMonad prim => MutableString (PrimState prim) -> Offset8 -> UTF8Char -> prim ()
writeUTF8Char :: MutableString (PrimState prim)
-> Offset Word8 -> UTF8Char -> prim ()
writeUTF8Char (MutableString MUArray Word8 (PrimState prim)
mba) Offset Word8
i (UTF8_1 Word8
x1) =
    MUArray Word8 (PrimState prim) -> Offset Word8 -> Word8 -> prim ()
forall (prim :: * -> *) ty.
(PrimMonad prim, PrimType ty) =>
MUArray ty (PrimState prim) -> Offset ty -> ty -> prim ()
Vec.unsafeWrite MUArray Word8 (PrimState prim)
mba Offset Word8
i     Word8
x1
writeUTF8Char (MutableString MUArray Word8 (PrimState prim)
mba) Offset Word8
i (UTF8_2 Word8
x1 Word8
x2) = do
    MUArray Word8 (PrimState prim) -> Offset Word8 -> Word8 -> prim ()
forall (prim :: * -> *) ty.
(PrimMonad prim, PrimType ty) =>
MUArray ty (PrimState prim) -> Offset ty -> ty -> prim ()
Vec.unsafeWrite MUArray Word8 (PrimState prim)
mba Offset Word8
i     Word8
x1
    MUArray Word8 (PrimState prim) -> Offset Word8 -> Word8 -> prim ()
forall (prim :: * -> *) ty.
(PrimMonad prim, PrimType ty) =>
MUArray ty (PrimState prim) -> Offset ty -> ty -> prim ()
Vec.unsafeWrite MUArray Word8 (PrimState prim)
mba (Offset Word8
iOffset Word8 -> Offset Word8 -> Offset Word8
forall a. Additive a => a -> a -> a
+Offset Word8
1) Word8
x2
writeUTF8Char (MutableString MUArray Word8 (PrimState prim)
mba) Offset Word8
i (UTF8_3 Word8
x1 Word8
x2 Word8
x3) = do
    MUArray Word8 (PrimState prim) -> Offset Word8 -> Word8 -> prim ()
forall (prim :: * -> *) ty.
(PrimMonad prim, PrimType ty) =>
MUArray ty (PrimState prim) -> Offset ty -> ty -> prim ()
Vec.unsafeWrite MUArray Word8 (PrimState prim)
mba Offset Word8
i     Word8
x1
    MUArray Word8 (PrimState prim) -> Offset Word8 -> Word8 -> prim ()
forall (prim :: * -> *) ty.
(PrimMonad prim, PrimType ty) =>
MUArray ty (PrimState prim) -> Offset ty -> ty -> prim ()
Vec.unsafeWrite MUArray Word8 (PrimState prim)
mba (Offset Word8
iOffset Word8 -> Offset Word8 -> Offset Word8
forall a. Additive a => a -> a -> a
+Offset Word8
1) Word8
x2
    MUArray Word8 (PrimState prim) -> Offset Word8 -> Word8 -> prim ()
forall (prim :: * -> *) ty.
(PrimMonad prim, PrimType ty) =>
MUArray ty (PrimState prim) -> Offset ty -> ty -> prim ()
Vec.unsafeWrite MUArray Word8 (PrimState prim)
mba (Offset Word8
iOffset Word8 -> Offset Word8 -> Offset Word8
forall a. Additive a => a -> a -> a
+Offset Word8
2) Word8
x3
writeUTF8Char (MutableString MUArray Word8 (PrimState prim)
mba) Offset Word8
i (UTF8_4 Word8
x1 Word8
x2 Word8
x3 Word8
x4) = do
    MUArray Word8 (PrimState prim) -> Offset Word8 -> Word8 -> prim ()
forall (prim :: * -> *) ty.
(PrimMonad prim, PrimType ty) =>
MUArray ty (PrimState prim) -> Offset ty -> ty -> prim ()
Vec.unsafeWrite MUArray Word8 (PrimState prim)
mba Offset Word8
i     Word8
x1
    MUArray Word8 (PrimState prim) -> Offset Word8 -> Word8 -> prim ()
forall (prim :: * -> *) ty.
(PrimMonad prim, PrimType ty) =>
MUArray ty (PrimState prim) -> Offset ty -> ty -> prim ()
Vec.unsafeWrite MUArray Word8 (PrimState prim)
mba (Offset Word8
iOffset Word8 -> Offset Word8 -> Offset Word8
forall a. Additive a => a -> a -> a
+Offset Word8
1) Word8
x2
    MUArray Word8 (PrimState prim) -> Offset Word8 -> Word8 -> prim ()
forall (prim :: * -> *) ty.
(PrimMonad prim, PrimType ty) =>
MUArray ty (PrimState prim) -> Offset ty -> ty -> prim ()
Vec.unsafeWrite MUArray Word8 (PrimState prim)
mba (Offset Word8
iOffset Word8 -> Offset Word8 -> Offset Word8
forall a. Additive a => a -> a -> a
+Offset Word8
2) Word8
x3
    MUArray Word8 (PrimState prim) -> Offset Word8 -> Word8 -> prim ()
forall (prim :: * -> *) ty.
(PrimMonad prim, PrimType ty) =>
MUArray ty (PrimState prim) -> Offset ty -> ty -> prim ()
Vec.unsafeWrite MUArray Word8 (PrimState prim)
mba (Offset Word8
iOffset Word8 -> Offset Word8 -> Offset Word8
forall a. Additive a => a -> a -> a
+Offset Word8
3) Word8
x4
{-# INLINE writeUTF8Char #-}

unsafeFreezeShrink :: PrimMonad prim => MutableString (PrimState prim) -> CountOf Word8 -> prim String
unsafeFreezeShrink :: MutableString (PrimState prim) -> CountOf Word8 -> prim String
unsafeFreezeShrink (MutableString MUArray Word8 (PrimState prim)
mba) CountOf Word8
s = UArray Word8 -> String
String (UArray Word8 -> String) -> prim (UArray Word8) -> prim String
forall (f :: * -> *) a b. Functor f => (a -> b) -> f a -> f b
<$> MUArray Word8 (PrimState prim)
-> CountOf Word8 -> prim (UArray Word8)
forall ty (prim :: * -> *).
(PrimType ty, PrimMonad prim) =>
MUArray ty (PrimState prim) -> CountOf ty -> prim (UArray ty)
Vec.unsafeFreezeShrink MUArray Word8 (PrimState prim)
mba CountOf Word8
s
{-# INLINE unsafeFreezeShrink #-}

------------------------------------------------------------------------
-- real functions

-- | Check if a String is null
null :: String -> Bool
null :: String -> Bool
null (String UArray Word8
ba) = UArray Word8 -> CountOf Word8
forall ty. UArray ty -> CountOf ty
C.length UArray Word8
ba CountOf Word8 -> CountOf Word8 -> Bool
forall a. Eq a => a -> a -> Bool
== CountOf Word8
0

-- we don't know in constant time the count of character in string,
-- however if we estimate bounds of what N characters would
-- take in space (between N and N*4). If the count is thus bigger than
-- the number of bytes, then we know for sure that it's going to
-- be out of bounds
countCharMoreThanBytes :: CountOf Char -> UArray Word8 -> Bool
countCharMoreThanBytes :: CountOf Char -> UArray Word8 -> Bool
countCharMoreThanBytes (CountOf Int
chars) UArray Word8
ba = Int
chars Int -> Int -> Bool
forall a. Ord a => a -> a -> Bool
>= Int
bytes
  where (CountOf Int
bytes) = UArray Word8 -> CountOf Word8
forall ty. UArray ty -> CountOf ty
C.length UArray Word8
ba

-- | Create a string composed of a number @n of Chars (Unicode code points).
--
-- if the input @s contains less characters than required, then the input string is returned.
take :: CountOf Char -> String -> String
take :: CountOf Char -> String -> String
take CountOf Char
n s :: String
s@(String UArray Word8
ba)
    | CountOf Char
n CountOf Char -> CountOf Char -> Bool
forall a. Ord a => a -> a -> Bool
<= CountOf Char
0                      = String
forall a. Monoid a => a
mempty
    | CountOf Char -> UArray Word8 -> Bool
countCharMoreThanBytes CountOf Char
n UArray Word8
ba = String
s
    | Bool
otherwise                   = UArray Word8 -> String
String (UArray Word8 -> String) -> UArray Word8 -> String
forall a b. (a -> b) -> a -> b
$ CountOf Word8 -> UArray Word8 -> UArray Word8
forall ty. CountOf ty -> UArray ty -> UArray ty
Vec.unsafeTake (Offset Word8 -> CountOf Word8
forall a. Offset a -> CountOf a
offsetAsSize (Offset Word8 -> CountOf Word8) -> Offset Word8 -> CountOf Word8
forall a b. (a -> b) -> a -> b
$ CountOf Char -> String -> Offset Word8
indexN CountOf Char
n String
s) UArray Word8
ba

-- | Create a string with the remaining Chars after dropping @n Chars from the beginning
drop :: CountOf Char -> String -> String
drop :: CountOf Char -> String -> String
drop CountOf Char
n s :: String
s@(String UArray Word8
ba)
    | CountOf Char
n CountOf Char -> CountOf Char -> Bool
forall a. Ord a => a -> a -> Bool
<= CountOf Char
0                      = String
s
    | CountOf Char -> UArray Word8 -> Bool
countCharMoreThanBytes CountOf Char
n UArray Word8
ba = String
forall a. Monoid a => a
mempty
    | Bool
otherwise                   = UArray Word8 -> String
String (UArray Word8 -> String) -> UArray Word8 -> String
forall a b. (a -> b) -> a -> b
$ CountOf Word8 -> UArray Word8 -> UArray Word8
forall ty. CountOf ty -> UArray ty -> UArray ty
Vec.drop (Offset Word8 -> CountOf Word8
forall a. Offset a -> CountOf a
offsetAsSize (Offset Word8 -> CountOf Word8) -> Offset Word8 -> CountOf Word8
forall a b. (a -> b) -> a -> b
$ CountOf Char -> String -> Offset Word8
indexN CountOf Char
n String
s) UArray Word8
ba

-- | Split a string at the Offset specified (in Char) returning both
-- the leading part and the remaining part.
splitAt :: CountOf Char -> String -> (String, String)
splitAt :: CountOf Char -> String -> (String, String)
splitAt CountOf Char
n s :: String
s@(String UArray Word8
ba)
    | CountOf Char
n CountOf Char -> CountOf Char -> Bool
forall a. Ord a => a -> a -> Bool
<= CountOf Char
0                      = (String
forall a. Monoid a => a
mempty, String
s)
    | CountOf Char -> UArray Word8 -> Bool
countCharMoreThanBytes CountOf Char
n UArray Word8
ba = (String
s, String
forall a. Monoid a => a
mempty)
    | Bool
otherwise                   =
        let (UArray Word8
v1,UArray Word8
v2) = CountOf Word8 -> UArray Word8 -> (UArray Word8, UArray Word8)
forall ty. CountOf ty -> UArray ty -> (UArray ty, UArray ty)
C.splitAt (Offset Word8 -> CountOf Word8
forall a. Offset a -> CountOf a
offsetAsSize (Offset Word8 -> CountOf Word8) -> Offset Word8 -> CountOf Word8
forall a b. (a -> b) -> a -> b
$ CountOf Char -> String -> Offset Word8
indexN CountOf Char
n String
s) UArray Word8
ba
         in (UArray Word8 -> String
String UArray Word8
v1, UArray Word8 -> String
String UArray Word8
v2)

-- | Return the offset (in bytes) of the N'th sequence in an UTF8 String
indexN :: CountOf Char -> String -> Offset Word8
indexN :: CountOf Char -> String -> Offset Word8
indexN !CountOf Char
n (String UArray Word8
ba) = (Block Word8 -> Offset Word8 -> Offset Word8)
-> (Ptr Word8 -> Offset Word8 -> ST Any (Offset Word8))
-> UArray Word8
-> Offset Word8
forall ty a s.
(Block ty -> Offset ty -> a)
-> (Ptr ty -> Offset ty -> ST s a) -> UArray ty -> a
Vec.unsafeDewrap Block Word8 -> Offset Word8 -> Offset Word8
goVec Ptr Word8 -> Offset Word8 -> ST Any (Offset Word8)
forall s. Ptr Word8 -> Offset Word8 -> ST s (Offset Word8)
goAddr UArray Word8
ba
  where
    goVec :: Block Word8 -> Offset Word8 -> Offset Word8
    goVec :: Block Word8 -> Offset Word8 -> Offset Word8
goVec (Block !ByteArray#
ma) !Offset Word8
start = Offset Word8 -> Offset Char -> Offset Word8
loop Offset Word8
start Offset Char
0
      where
        !len :: Offset Word8
len = Offset Word8
start Offset Word8 -> CountOf Word8 -> Offset Word8
forall ty. Offset ty -> CountOf ty -> Offset ty
`offsetPlusE` UArray Word8 -> CountOf Word8
forall ty. UArray ty -> CountOf ty
Vec.length UArray Word8
ba
        loop :: Offset Word8 -> Offset Char -> Offset Word8
        loop :: Offset Word8 -> Offset Char -> Offset Word8
loop !Offset Word8
idx !Offset Char
i
            | Offset Word8
idx Offset Word8 -> Offset Word8 -> Bool
forall a. Ord a => a -> a -> Bool
>= Offset Word8
len Bool -> Bool -> Bool
|| Offset Char
i Offset Char -> CountOf Char -> Bool
forall ty. Offset ty -> CountOf ty -> Bool
.==# CountOf Char
n = CountOf Word8 -> Offset Word8
forall a. CountOf a -> Offset a
sizeAsOffset (Offset Word8
idx Offset Word8 -> Offset Word8 -> Difference (Offset Word8)
forall a. Subtractive a => a -> a -> Difference a
- Offset Word8
start)
            | Bool
otherwise              = Offset Word8 -> Offset Char -> Offset Word8
loop (Offset Word8
idx Offset Word8 -> CountOf Word8 -> Offset Word8
forall ty. Offset ty -> CountOf ty -> Offset ty
`offsetPlusE` CountOf Word8
d) (Offset Char
i Offset Char -> Offset Char -> Offset Char
forall a. Additive a => a -> a -> a
+ Int -> Offset Char
forall ty. Int -> Offset ty
Offset Int
1)
          where d :: CountOf Word8
d = Word8 -> CountOf Word8
skipNextHeaderValue (ByteArray# -> Offset Word8 -> Word8
forall ty. PrimType ty => ByteArray# -> Offset ty -> ty
primBaIndex ByteArray#
ma Offset Word8
idx)
    {-# INLINE goVec #-}

    goAddr :: Ptr Word8 -> Offset Word8 -> ST s (Offset Word8)
    goAddr :: Ptr Word8 -> Offset Word8 -> ST s (Offset Word8)
goAddr (Ptr Addr#
ptr) !Offset Word8
start = Offset Word8 -> ST s (Offset Word8)
forall (m :: * -> *) a. Monad m => a -> m a
return (Offset Word8 -> ST s (Offset Word8))
-> Offset Word8 -> ST s (Offset Word8)
forall a b. (a -> b) -> a -> b
$ Offset Word8 -> Offset Char -> Offset Word8
loop Offset Word8
start (Int -> Offset Char
forall ty. Int -> Offset ty
Offset Int
0)
      where
        !len :: Offset Word8
len = Offset Word8
start Offset Word8 -> CountOf Word8 -> Offset Word8
forall ty. Offset ty -> CountOf ty -> Offset ty
`offsetPlusE` UArray Word8 -> CountOf Word8
forall ty. UArray ty -> CountOf ty
Vec.length UArray Word8
ba
        loop :: Offset Word8 -> Offset Char -> Offset Word8
        loop :: Offset Word8 -> Offset Char -> Offset Word8
loop !Offset Word8
idx !Offset Char
i
            | Offset Word8
idx Offset Word8 -> Offset Word8 -> Bool
forall a. Ord a => a -> a -> Bool
>= Offset Word8
len Bool -> Bool -> Bool
|| Offset Char
i Offset Char -> CountOf Char -> Bool
forall ty. Offset ty -> CountOf ty -> Bool
.==# CountOf Char
n = CountOf Word8 -> Offset Word8
forall a. CountOf a -> Offset a
sizeAsOffset (Offset Word8
idx Offset Word8 -> Offset Word8 -> Difference (Offset Word8)
forall a. Subtractive a => a -> a -> Difference a
- Offset Word8
start)
            | Bool
otherwise              = Offset Word8 -> Offset Char -> Offset Word8
loop (Offset Word8
idx Offset Word8 -> CountOf Word8 -> Offset Word8
forall ty. Offset ty -> CountOf ty -> Offset ty
`offsetPlusE` CountOf Word8
d) (Offset Char
i Offset Char -> Offset Char -> Offset Char
forall a. Additive a => a -> a -> a
+ Int -> Offset Char
forall ty. Int -> Offset ty
Offset Int
1)
          where d :: CountOf Word8
d = Word8 -> CountOf Word8
skipNextHeaderValue (Addr# -> Offset Word8 -> Word8
forall ty. PrimType ty => Addr# -> Offset ty -> ty
primAddrIndex Addr#
ptr Offset Word8
idx)
    {-# INLINE goAddr #-}
{-# INLINE indexN #-}

-- inverse a CountOf that is specified from the end (e.g. take n Chars from the end)
--
-- rev{Take,Drop,SplitAt} TODO optimise:
-- we can process the string from the end using a skipPrev instead of getting the length
countFromStart :: String -> CountOf Char -> CountOf Char
countFromStart :: String -> CountOf Char -> CountOf Char
countFromStart String
s sz :: CountOf Char
sz@(CountOf Int
sz')
    | CountOf Char
sz CountOf Char -> CountOf Char -> Bool
forall a. Ord a => a -> a -> Bool
>= CountOf Char
len = Int -> CountOf Char
forall ty. Int -> CountOf ty
CountOf Int
0
    | Bool
otherwise = Int -> CountOf Char
forall ty. Int -> CountOf ty
CountOf (Int
len' Int -> Int -> Difference Int
forall a. Subtractive a => a -> a -> Difference a
- Int
sz')
  where len :: CountOf Char
len@(CountOf Int
len') = String -> CountOf Char
length String
s

-- | Similar to 'take' but from the end
revTake :: CountOf Char -> String -> String
revTake :: CountOf Char -> String -> String
revTake CountOf Char
n String
v = CountOf Char -> String -> String
drop (String -> CountOf Char -> CountOf Char
countFromStart String
v CountOf Char
n) String
v

-- | Similar to 'drop' but from the end
revDrop :: CountOf Char -> String -> String
revDrop :: CountOf Char -> String -> String
revDrop CountOf Char
n String
v = CountOf Char -> String -> String
take (String -> CountOf Char -> CountOf Char
countFromStart String
v CountOf Char
n) String
v

-- | Similar to 'splitAt' but from the end
revSplitAt :: CountOf Char -> String -> (String, String)
revSplitAt :: CountOf Char -> String -> (String, String)
revSplitAt CountOf Char
n String
v = (CountOf Char -> String -> String
drop CountOf Char
idx String
v, CountOf Char -> String -> String
take CountOf Char
idx String
v) where idx :: CountOf Char
idx = String -> CountOf Char -> CountOf Char
countFromStart String
v CountOf Char
n

-- | Split on the input string using the predicate as separator
--
-- e.g.
--
-- > splitOn (== ',') ","          == ["",""]
-- > splitOn (== ',') ",abc,"      == ["","abc",""]
-- > splitOn (== ':') "abc"        == ["abc"]
-- > splitOn (== ':') "abc::def"   == ["abc","","def"]
-- > splitOn (== ':') "::abc::def" == ["","","abc","","def"]
--
splitOn :: (Char -> Bool) -> String -> [String]
splitOn :: (Char -> Bool) -> String -> [String]
splitOn Char -> Bool
predicate String
s
    | CountOf Word8
sz CountOf Word8 -> CountOf Word8 -> Bool
forall a. Eq a => a -> a -> Bool
== Int -> CountOf Word8
forall ty. Int -> CountOf ty
CountOf Int
0 = [String
forall a. Monoid a => a
mempty]
    | Bool
otherwise    = Offset Word8 -> Offset Word8 -> [String]
loop Offset Word8
forall a. Additive a => a
azero Offset Word8
forall a. Additive a => a
azero
  where
    !sz :: CountOf Word8
sz = String -> CountOf Word8
size String
s
    end :: Offset Word8
end = Offset Word8
forall a. Additive a => a
azero Offset Word8 -> CountOf Word8 -> Offset Word8
forall ty. Offset ty -> CountOf ty -> Offset ty
`offsetPlusE` CountOf Word8
sz
    loop :: Offset Word8 -> Offset Word8 -> [String]
loop Offset Word8
prevIdx Offset Word8
idx
        | Offset Word8
idx Offset Word8 -> Offset Word8 -> Bool
forall a. Eq a => a -> a -> Bool
== Offset Word8
end = [String -> Offset Word8 -> Offset Word8 -> String
sub String
s Offset Word8
prevIdx Offset Word8
idx]
        | Bool
otherwise =
            let !(Step Char
c Offset Word8
idx') = String -> Offset Word8 -> Step
next String
s Offset Word8
idx
             in if Char -> Bool
predicate Char
c
                    then String -> Offset Word8 -> Offset Word8 -> String
sub String
s Offset Word8
prevIdx Offset Word8
idx String -> [String] -> [String]
forall a. a -> [a] -> [a]
: Offset Word8 -> Offset Word8 -> [String]
loop Offset Word8
idx' Offset Word8
idx'
                    else Offset Word8 -> Offset Word8 -> [String]
loop Offset Word8
prevIdx Offset Word8
idx'

-- | Internal call to make a substring given offset in bytes.
--
-- This is unsafe considering that one can create a substring
-- starting and/or ending on the middle of a UTF8 sequence.
sub :: String -> Offset8 -> Offset8 -> String
sub :: String -> Offset Word8 -> Offset Word8 -> String
sub (String UArray Word8
ba) Offset Word8
start Offset Word8
end = UArray Word8 -> String
String (UArray Word8 -> String) -> UArray Word8 -> String
forall a b. (a -> b) -> a -> b
$ UArray Word8 -> Offset Word8 -> Offset Word8 -> UArray Word8
forall ty.
PrimType ty =>
UArray ty -> Offset ty -> Offset ty -> UArray ty
Vec.sub UArray Word8
ba Offset Word8
start Offset Word8
end

-- | Internal call to split at a given index in offset of bytes.
--
-- This is unsafe considering that one can split in the middle of a
-- UTF8 sequence, so use with care.
splitIndex :: Offset8 -> String -> (String, String)
splitIndex :: Offset Word8 -> String -> (String, String)
splitIndex Offset Word8
idx (String UArray Word8
ba) = (UArray Word8 -> String
String UArray Word8
v1, UArray Word8 -> String
String UArray Word8
v2)
  where (UArray Word8
v1,UArray Word8
v2) = CountOf Word8 -> UArray Word8 -> (UArray Word8, UArray Word8)
forall ty. CountOf ty -> UArray ty -> (UArray ty, UArray ty)
C.splitAt (Offset Word8 -> CountOf Word8
forall a. Offset a -> CountOf a
offsetAsSize Offset Word8
idx) UArray Word8
ba

-- | Break a string into 2 strings at the location where the predicate return True
break :: (Char -> Bool) -> String -> (String, String)
break :: (Char -> Bool) -> String -> (String, String)
break Char -> Bool
predicate s :: String
s@(String UArray Word8
ba) = (forall s. ST s (String, String)) -> (String, String)
forall a. (forall s. ST s a) -> a
runST ((forall s. ST s (String, String)) -> (String, String))
-> (forall s. ST s (String, String)) -> (String, String)
forall a b. (a -> b) -> a -> b
$ UArray Word8
-> ((Offset Word8 -> Word8) -> ST s (String, String))
-> ST s (String, String)
forall (prim :: * -> *) ty a.
(PrimMonad prim, PrimType ty) =>
UArray ty -> ((Offset ty -> ty) -> prim a) -> prim a
Vec.unsafeIndexer UArray Word8
ba (Offset Word8 -> Word8) -> ST s (String, String)
forall st. (Offset Word8 -> Word8) -> ST st (String, String)
go
  where
    !sz :: CountOf Word8
sz = String -> CountOf Word8
size String
s
    end :: Offset Word8
end = Offset Word8
forall a. Additive a => a
azero Offset Word8 -> CountOf Word8 -> Offset Word8
forall ty. Offset ty -> CountOf ty -> Offset ty
`offsetPlusE` CountOf Word8
sz

    go :: (Offset Word8 -> Word8) -> ST st (String, String)
    go :: (Offset Word8 -> Word8) -> ST st (String, String)
go Offset Word8 -> Word8
getIdx = Offset Word8 -> ST st (String, String)
loop (Int -> Offset Word8
forall ty. Int -> Offset ty
Offset Int
0)
      where
        !nextI :: Offset Word8 -> (Char, Offset Word8)
nextI = (Offset Word8 -> Word8) -> Offset Word8 -> (Char, Offset Word8)
nextWithIndexer Offset Word8 -> Word8
getIdx
        loop :: Offset Word8 -> ST st (String, String)
loop Offset Word8
idx
            | Offset Word8
idx Offset Word8 -> Offset Word8 -> Bool
forall a. Eq a => a -> a -> Bool
== Offset Word8
end = (String, String) -> ST st (String, String)
forall (m :: * -> *) a. Monad m => a -> m a
return (String
s, String
forall a. Monoid a => a
mempty)
            | Bool
otherwise  = do
                let (Char
c, Offset Word8
idx') = Offset Word8 -> (Char, Offset Word8)
nextI Offset Word8
idx
                case Char -> Bool
predicate Char
c of
                    Bool
True  -> (String, String) -> ST st (String, String)
forall (m :: * -> *) a. Monad m => a -> m a
return ((String, String) -> ST st (String, String))
-> (String, String) -> ST st (String, String)
forall a b. (a -> b) -> a -> b
$ Offset Word8 -> String -> (String, String)
splitIndex Offset Word8
idx String
s
                    Bool
False -> Offset Word8 -> ST st (String, String)
loop Offset Word8
idx'
        {-# INLINE loop #-}
{-# INLINE [2] break #-}

breakEnd :: (Char -> Bool) -> String -> (String, String)
breakEnd :: (Char -> Bool) -> String -> (String, String)
breakEnd Char -> Bool
predicate s :: String
s@(String UArray Word8
arr)
    | Offset Word8
k Offset Word8 -> Offset Word8 -> Bool
forall a. Eq a => a -> a -> Bool
== Offset Word8
end  = (String
s, String
forall a. Monoid a => a
mempty)
    | Bool
otherwise = Offset Word8 -> String -> (String, String)
splitIndex (Offset Word8
k Offset Word8 -> Offset Word8 -> Offset Word8
forall a. Offset a -> Offset a -> Offset a
`offsetSub` Offset Word8
start) String
s
  where
    k :: Offset Word8
k = (Block Word8 -> Offset Word8)
-> (FinalPtr Word8 -> Ptr Word8 -> ST Any (Offset Word8))
-> UArray Word8
-> Offset Word8
forall ty a s.
(Block ty -> a)
-> (FinalPtr ty -> Ptr ty -> ST s a) -> UArray ty -> a
C.onBackend Block Word8 -> Offset Word8
goVec (\FinalPtr Word8
_ -> Offset Word8 -> ST Any (Offset Word8)
forall (f :: * -> *) a. Applicative f => a -> f a
pure (Offset Word8 -> ST Any (Offset Word8))
-> (Ptr Word8 -> Offset Word8)
-> Ptr Word8
-> ST Any (Offset Word8)
forall k (cat :: k -> k -> *) (b :: k) (c :: k) (a :: k).
Category cat =>
cat b c -> cat a b -> cat a c
. Ptr Word8 -> Offset Word8
goAddr) UArray Word8
arr
    (C.ValidRange !Offset Word8
start !Offset Word8
end) = UArray Word8 -> ValidRange Word8
forall ty. UArray ty -> ValidRange ty
offsetsValidRange UArray Word8
arr
    goVec :: Block Word8 -> Offset Word8
goVec ba :: Block Word8
ba@(Block !ByteArray#
_) = let k :: Offset Word8
k = (Char -> Bool)
-> Block Word8 -> Offset Word8 -> Offset Word8 -> Offset Word8
forall container.
Indexable container Word8 =>
(Char -> Bool)
-> container -> Offset Word8 -> Offset Word8 -> Offset Word8
Alg.revFindIndexPredicate Char -> Bool
predicate Block Word8
ba Offset Word8
start Offset Word8
end
                        in if Offset Word8
k Offset Word8 -> Offset Word8 -> Bool
forall a. Eq a => a -> a -> Bool
== Offset Word8
end then Offset Word8
end else Block Word8 -> Offset Word8 -> Offset Word8
forall container.
Indexable container Word8 =>
container -> Offset Word8 -> Offset Word8
UTF8.nextSkip Block Word8
ba Offset Word8
k
    goAddr :: Ptr Word8 -> Offset Word8
goAddr ptr :: Ptr Word8
ptr@(Ptr !Addr#
_) =
        let k :: Offset Word8
k = (Char -> Bool)
-> Ptr Word8 -> Offset Word8 -> Offset Word8 -> Offset Word8
forall container.
Indexable container Word8 =>
(Char -> Bool)
-> container -> Offset Word8 -> Offset Word8 -> Offset Word8
Alg.revFindIndexPredicate Char -> Bool
predicate Ptr Word8
ptr Offset Word8
start Offset Word8
end
         in if Offset Word8
k Offset Word8 -> Offset Word8 -> Bool
forall a. Eq a => a -> a -> Bool
== Offset Word8
end then Offset Word8
end else Ptr Word8 -> Offset Word8 -> Offset Word8
forall container.
Indexable container Word8 =>
container -> Offset Word8 -> Offset Word8
UTF8.nextSkip Ptr Word8
ptr Offset Word8
k
{-# INLINE [2] breakEnd #-}

#if MIN_VERSION_base(4,9,0)
{-# RULES "break (== 'c')" [3] forall c . break (eqChar c) = breakElem c #-}
#else
{-# RULES "break (== 'c')" [3] forall c . break (== c) = breakElem c #-}
#endif

-- | Break a string into 2 strings at the first occurence of the character
breakElem :: Char -> String -> (String, String)
breakElem :: Char -> String -> (String, String)
breakElem !Char
el s :: String
s@(String UArray Word8
ba)
    | CountOf Word8
sz CountOf Word8 -> CountOf Word8 -> Bool
forall a. Eq a => a -> a -> Bool
== CountOf Word8
0   = (String
forall a. Monoid a => a
mempty, String
forall a. Monoid a => a
mempty)
    | Bool
otherwise =
        case Char -> UTF8Char
asUTF8Char Char
el of
            UTF8_1 Word8
w -> let !(UArray Word8
v1,UArray Word8
v2) = Word8 -> UArray Word8 -> (UArray Word8, UArray Word8)
forall ty. PrimType ty => ty -> UArray ty -> (UArray ty, UArray ty)
Vec.breakElem Word8
w UArray Word8
ba in (UArray Word8 -> String
String UArray Word8
v1, UArray Word8 -> String
String UArray Word8
v2)
            UTF8Char
_        -> (forall s. ST s (String, String)) -> (String, String)
forall a. (forall s. ST s a) -> a
runST ((forall s. ST s (String, String)) -> (String, String))
-> (forall s. ST s (String, String)) -> (String, String)
forall a b. (a -> b) -> a -> b
$ UArray Word8
-> ((Offset Word8 -> Word8) -> ST s (String, String))
-> ST s (String, String)
forall (prim :: * -> *) ty a.
(PrimMonad prim, PrimType ty) =>
UArray ty -> ((Offset ty -> ty) -> prim a) -> prim a
Vec.unsafeIndexer UArray Word8
ba (Offset Word8 -> Word8) -> ST s (String, String)
forall st. (Offset Word8 -> Word8) -> ST st (String, String)
go
  where
    sz :: CountOf Word8
sz = String -> CountOf Word8
size String
s
    end :: Offset Word8
end = Offset Word8
forall a. Additive a => a
azero Offset Word8 -> CountOf Word8 -> Offset Word8
forall ty. Offset ty -> CountOf ty -> Offset ty
`offsetPlusE` CountOf Word8
sz

    go :: (Offset Word8 -> Word8) -> ST st (String, String)
    go :: (Offset Word8 -> Word8) -> ST st (String, String)
go Offset Word8 -> Word8
getIdx = Offset Word8 -> ST st (String, String)
loop (Int -> Offset Word8
forall ty. Int -> Offset ty
Offset Int
0)
      where
        !nextI :: Offset Word8 -> (Char, Offset Word8)
nextI = (Offset Word8 -> Word8) -> Offset Word8 -> (Char, Offset Word8)
nextWithIndexer Offset Word8 -> Word8
getIdx
        loop :: Offset Word8 -> ST st (String, String)
loop Offset Word8
idx
            | Offset Word8
idx Offset Word8 -> Offset Word8 -> Bool
forall a. Eq a => a -> a -> Bool
== Offset Word8
end = (String, String) -> ST st (String, String)
forall (m :: * -> *) a. Monad m => a -> m a
return (String
s, String
forall a. Monoid a => a
mempty)
            | Bool
otherwise  = do
                let (Char
c, Offset Word8
idx') = Offset Word8 -> (Char, Offset Word8)
nextI Offset Word8
idx
                case Char
el Char -> Char -> Bool
forall a. Eq a => a -> a -> Bool
== Char
c of
                    Bool
True  -> (String, String) -> ST st (String, String)
forall (m :: * -> *) a. Monad m => a -> m a
return ((String, String) -> ST st (String, String))
-> (String, String) -> ST st (String, String)
forall a b. (a -> b) -> a -> b
$ Offset Word8 -> String -> (String, String)
splitIndex Offset Word8
idx String
s
                    Bool
False -> Offset Word8 -> ST st (String, String)
loop Offset Word8
idx'

-- | Same as break but cut on a line feed with an optional carriage return.
--
-- This is the same operation as 'breakElem LF' dropping the last character of the
-- string if it's a CR.
--
-- Also for efficiency reason (streaming), it returns if the last character was a CR character.
breakLine :: String -> Either Bool (String, String)
breakLine :: String -> Either Bool (String, String)
breakLine (String UArray Word8
arr) = (UArray Word8 -> String)
-> (UArray Word8 -> String)
-> (UArray Word8, UArray Word8)
-> (String, String)
forall (p :: * -> * -> *) a b c d.
Bifunctor p =>
(a -> b) -> (c -> d) -> p a c -> p b d
bimap UArray Word8 -> String
String UArray Word8 -> String
String ((UArray Word8, UArray Word8) -> (String, String))
-> Either Bool (UArray Word8, UArray Word8)
-> Either Bool (String, String)
forall (f :: * -> *) a b. Functor f => (a -> b) -> f a -> f b
<$> UArray Word8 -> Either Bool (UArray Word8, UArray Word8)
Vec.breakLine UArray Word8
arr

-- | Apply a @predicate@ to the string to return the longest prefix that satisfy the predicate and
-- the remaining
span :: (Char -> Bool) -> String -> (String, String)
span :: (Char -> Bool) -> String -> (String, String)
span Char -> Bool
predicate String
s = (Char -> Bool) -> String -> (String, String)
break (Bool -> Bool
not (Bool -> Bool) -> (Char -> Bool) -> Char -> Bool
forall k (cat :: k -> k -> *) (b :: k) (c :: k) (a :: k).
Category cat =>
cat b c -> cat a b -> cat a c
. Char -> Bool
predicate) String
s

-- | Apply a @predicate@ to the string to return the longest suffix that satisfy the predicate and
-- the remaining
spanEnd :: (Char -> Bool) -> String -> (String, String)
spanEnd :: (Char -> Bool) -> String -> (String, String)
spanEnd Char -> Bool
predicate String
s = (Char -> Bool) -> String -> (String, String)
breakEnd (Bool -> Bool
not (Bool -> Bool) -> (Char -> Bool) -> Char -> Bool
forall k (cat :: k -> k -> *) (b :: k) (c :: k) (a :: k).
Category cat =>
cat b c -> cat a b -> cat a c
. Char -> Bool
predicate) String
s

-- | Drop character from the beginning while the predicate is true
dropWhile :: (Char -> Bool) -> String -> String
dropWhile :: (Char -> Bool) -> String -> String
dropWhile Char -> Bool
predicate = (String, String) -> String
forall a b. (a, b) -> b
snd ((String, String) -> String)
-> (String -> (String, String)) -> String -> String
forall k (cat :: k -> k -> *) (b :: k) (c :: k) (a :: k).
Category cat =>
cat b c -> cat a b -> cat a c
. (Char -> Bool) -> String -> (String, String)
break (Bool -> Bool
not (Bool -> Bool) -> (Char -> Bool) -> Char -> Bool
forall k (cat :: k -> k -> *) (b :: k) (c :: k) (a :: k).
Category cat =>
cat b c -> cat a b -> cat a c
. Char -> Bool
predicate)

-- | Return whereas the string contains a specific character or not
elem :: Char -> String -> Bool
elem :: Char -> String -> Bool
elem !Char
el s :: String
s@(String UArray Word8
ba) =
    case Char -> UTF8Char
asUTF8Char Char
el of
        UTF8_1 Word8
w -> Word8 -> UArray Word8 -> Bool
forall ty. PrimType ty => ty -> UArray ty -> Bool
Vec.elem Word8
w UArray Word8
ba
        UTF8Char
_        -> (forall s. ST s Bool) -> Bool
forall a. (forall s. ST s a) -> a
runST ((forall s. ST s Bool) -> Bool) -> (forall s. ST s Bool) -> Bool
forall a b. (a -> b) -> a -> b
$ UArray Word8 -> ((Offset Word8 -> Word8) -> ST s Bool) -> ST s Bool
forall (prim :: * -> *) ty a.
(PrimMonad prim, PrimType ty) =>
UArray ty -> ((Offset ty -> ty) -> prim a) -> prim a
Vec.unsafeIndexer UArray Word8
ba (Offset Word8 -> Word8) -> ST s Bool
forall st. (Offset Word8 -> Word8) -> ST st Bool
go
  where
    sz :: CountOf Word8
sz = String -> CountOf Word8
size String
s
    end :: Offset Word8
end = Offset Word8
forall a. Additive a => a
azero Offset Word8 -> CountOf Word8 -> Offset Word8
forall ty. Offset ty -> CountOf ty -> Offset ty
`offsetPlusE` CountOf Word8
sz

    go :: (Offset Word8 -> Word8) -> ST st Bool
    go :: (Offset Word8 -> Word8) -> ST st Bool
go Offset Word8 -> Word8
getIdx = Offset Word8 -> ST st Bool
loop (Int -> Offset Word8
forall ty. Int -> Offset ty
Offset Int
0)
      where
        !nextI :: Offset Word8 -> (Char, Offset Word8)
nextI = (Offset Word8 -> Word8) -> Offset Word8 -> (Char, Offset Word8)
nextWithIndexer Offset Word8 -> Word8
getIdx
        loop :: Offset Word8 -> ST st Bool
loop !Offset Word8
idx
            | Offset Word8
idx Offset Word8 -> Offset Word8 -> Bool
forall a. Eq a => a -> a -> Bool
== Offset Word8
end = Bool -> ST st Bool
forall (m :: * -> *) a. Monad m => a -> m a
return Bool
False
            | Bool
otherwise  = do
                let (Char
c, Offset Word8
idx') = Offset Word8 -> (Char, Offset Word8)
nextI Offset Word8
idx
                case Char
el Char -> Char -> Bool
forall a. Eq a => a -> a -> Bool
== Char
c of
                    Bool
True  -> Bool -> ST st Bool
forall (m :: * -> *) a. Monad m => a -> m a
return Bool
True
                    Bool
False -> Offset Word8 -> ST st Bool
loop Offset Word8
idx'

-- | Intersperse the character @sep@ between each character in the string
--
-- > intersperse ' ' "Hello Foundation"
-- "H e l l o   F o u n d a t i o n"
intersperse :: Char -> String -> String
intersperse :: Char -> String -> String
intersperse Char
sep String
src = case String -> CountOf Char
length String
src CountOf Char -> CountOf Char -> Difference (CountOf Char)
forall a. Subtractive a => a -> a -> Difference a
- CountOf Char
1 of
    Difference (CountOf Char)
Nothing   -> String
src
    Just 0    -> String
src
    Just gaps -> (forall s. ST s String) -> String
forall a. (forall s. ST s a) -> a
runST ((forall s. ST s String) -> String)
-> (forall s. ST s String) -> String
forall a b. (a -> b) -> a -> b
$ String
-> CountOf Word8
-> (String
    -> Offset Char
    -> Offset Word8
    -> MutableString s
    -> Offset Word8
    -> ST s (Offset Word8, Offset Word8))
-> ST s String
forall s.
String
-> CountOf Word8
-> (String
    -> Offset Char
    -> Offset Word8
    -> MutableString s
    -> Offset Word8
    -> ST s (Offset Word8, Offset Word8))
-> ST s String
unsafeCopyFrom String
src CountOf Word8
dstBytes String
-> Offset Char
-> Offset Word8
-> MutableString s
-> Offset Word8
-> ST s (Offset Word8, Offset Word8)
forall s.
String
-> Offset Char
-> Offset Word8
-> MutableString s
-> Offset Word8
-> ST s (Offset Word8, Offset Word8)
go
        where
          lastSrcI :: Offset Char
          lastSrcI :: Offset Char
lastSrcI = Offset Char
0 Offset Char -> CountOf Char -> Offset Char
forall ty. Offset ty -> CountOf ty -> Offset ty
`offsetPlusE` CountOf Char
gaps
          dstBytes :: CountOf Word8
dstBytes = (String -> CountOf Word8
size String
src :: CountOf Word8) CountOf Word8 -> CountOf Word8 -> CountOf Word8
forall a. Additive a => a -> a -> a
+ (CountOf Char
gaps CountOf Char -> CountOf Word8 -> CountOf Word8
forall a n. (Additive a, IsNatural n) => n -> a -> a
`scale` Int -> CountOf Word8
charToBytes (Char -> Int
forall a. Enum a => a -> Int
fromEnum Char
sep))

          go :: String -> Offset Char -> Offset8 -> MutableString s -> Offset8 -> ST s (Offset8, Offset8)
          go :: String
-> Offset Char
-> Offset Word8
-> MutableString s
-> Offset Word8
-> ST s (Offset Word8, Offset Word8)
go String
src' Offset Char
srcI Offset Word8
srcIdx MutableString s
dst Offset Word8
dstIdx
              | Offset Char
srcI Offset Char -> Offset Char -> Bool
forall a. Eq a => a -> a -> Bool
== Offset Char
lastSrcI = do
                  Offset Word8
nextDstIdx <- MutableString (PrimState (ST s))
-> Offset Word8 -> Char -> ST s (Offset Word8)
forall (prim :: * -> *).
PrimMonad prim =>
MutableString (PrimState prim)
-> Offset Word8 -> Char -> prim (Offset Word8)
write MutableString s
MutableString (PrimState (ST s))
dst Offset Word8
dstIdx Char
c
                  (Offset Word8, Offset Word8) -> ST s (Offset Word8, Offset Word8)
forall (m :: * -> *) a. Monad m => a -> m a
return (Offset Word8
nextSrcIdx, Offset Word8
nextDstIdx)
              | Bool
otherwise        = do
                  Offset Word8
nextDstIdx  <- MutableString (PrimState (ST s))
-> Offset Word8 -> Char -> ST s (Offset Word8)
forall (prim :: * -> *).
PrimMonad prim =>
MutableString (PrimState prim)
-> Offset Word8 -> Char -> prim (Offset Word8)
write MutableString s
MutableString (PrimState (ST s))
dst Offset Word8
dstIdx Char
c
                  Offset Word8
nextDstIdx' <- MutableString (PrimState (ST s))
-> Offset Word8 -> Char -> ST s (Offset Word8)
forall (prim :: * -> *).
PrimMonad prim =>
MutableString (PrimState prim)
-> Offset Word8 -> Char -> prim (Offset Word8)
write MutableString s
MutableString (PrimState (ST s))
dst Offset Word8
nextDstIdx Char
sep
                  (Offset Word8, Offset Word8) -> ST s (Offset Word8, Offset Word8)
forall (m :: * -> *) a. Monad m => a -> m a
return (Offset Word8
nextSrcIdx, Offset Word8
nextDstIdx')
            where
              !(Step Char
c Offset Word8
nextSrcIdx) = String -> Offset Word8 -> Step
next String
src' Offset Word8
srcIdx

-- | Allocate a new @String@ with a fill function that has access to the characters of
--   the source @String@.
unsafeCopyFrom :: String -- ^ Source string
               -> CountOf Word8  -- ^ Length of the destination string in bytes
               -> (String -> Offset Char -> Offset8 -> MutableString s -> Offset8 -> ST s (Offset8, Offset8))
               -- ^ Function called for each character in the source String
               -> ST s String -- ^ Returns the filled new string
unsafeCopyFrom :: String
-> CountOf Word8
-> (String
    -> Offset Char
    -> Offset Word8
    -> MutableString s
    -> Offset Word8
    -> ST s (Offset Word8, Offset Word8))
-> ST s String
unsafeCopyFrom String
src CountOf Word8
dstBytes String
-> Offset Char
-> Offset Word8
-> MutableString s
-> Offset Word8
-> ST s (Offset Word8, Offset Word8)
f = CountOf Word8 -> ST s (MutableString (PrimState (ST s)))
forall (prim :: * -> *).
PrimMonad prim =>
CountOf Word8 -> prim (MutableString (PrimState prim))
new CountOf Word8
dstBytes ST s (MutableString s)
-> (MutableString s -> ST s (MutableString s))
-> ST s (MutableString s)
forall (m :: * -> *) a b. Monad m => m a -> (a -> m b) -> m b
>>= Offset Char
-> Offset Word8
-> Offset Word8
-> (String
    -> Offset Char
    -> Offset Word8
    -> MutableString s
    -> Offset Word8
    -> ST s (Offset Word8, Offset Word8))
-> MutableString s
-> ST s (MutableString s)
fill (Int -> Offset Char
forall ty. Int -> Offset ty
Offset Int
0) (Int -> Offset Word8
forall ty. Int -> Offset ty
Offset Int
0) (Int -> Offset Word8
forall ty. Int -> Offset ty
Offset Int
0) String
-> Offset Char
-> Offset Word8
-> MutableString s
-> Offset Word8
-> ST s (Offset Word8, Offset Word8)
f ST s (MutableString s)
-> (MutableString s -> ST s String) -> ST s String
forall (m :: * -> *) a b. Monad m => m a -> (a -> m b) -> m b
>>= MutableString s -> ST s String
forall (prim :: * -> *).
PrimMonad prim =>
MutableString (PrimState prim) -> prim String
freeze
  where
    srcLen :: CountOf Char
srcLen = String -> CountOf Char
length String
src
    end :: Offset Char
end = Int -> Offset Char
forall ty. Int -> Offset ty
Offset Int
0 Offset Char -> CountOf Char -> Offset Char
forall ty. Offset ty -> CountOf ty -> Offset ty
`offsetPlusE` CountOf Char
srcLen
    fill :: Offset Char
-> Offset Word8
-> Offset Word8
-> (String
    -> Offset Char
    -> Offset Word8
    -> MutableString s
    -> Offset Word8
    -> ST s (Offset Word8, Offset Word8))
-> MutableString s
-> ST s (MutableString s)
fill Offset Char
srcI Offset Word8
srcIdx Offset Word8
dstIdx String
-> Offset Char
-> Offset Word8
-> MutableString s
-> Offset Word8
-> ST s (Offset Word8, Offset Word8)
f' MutableString s
dst'
        | Offset Char
srcI Offset Char -> Offset Char -> Bool
forall a. Eq a => a -> a -> Bool
== Offset Char
end = MutableString s -> ST s (MutableString s)
forall (m :: * -> *) a. Monad m => a -> m a
return MutableString s
dst'
        | Bool
otherwise = do (Offset Word8
nextSrcIdx, Offset Word8
nextDstIdx) <- String
-> Offset Char
-> Offset Word8
-> MutableString s
-> Offset Word8
-> ST s (Offset Word8, Offset Word8)
f' String
src Offset Char
srcI Offset Word8
srcIdx MutableString s
dst' Offset Word8
dstIdx
                         Offset Char
-> Offset Word8
-> Offset Word8
-> (String
    -> Offset Char
    -> Offset Word8
    -> MutableString s
    -> Offset Word8
    -> ST s (Offset Word8, Offset Word8))
-> MutableString s
-> ST s (MutableString s)
fill (Offset Char
srcI Offset Char -> Offset Char -> Offset Char
forall a. Additive a => a -> a -> a
+ Int -> Offset Char
forall ty. Int -> Offset ty
Offset Int
1) Offset Word8
nextSrcIdx Offset Word8
nextDstIdx String
-> Offset Char
-> Offset Word8
-> MutableString s
-> Offset Word8
-> ST s (Offset Word8, Offset Word8)
f' MutableString s
dst'

-- | Length of a String using CountOf
--
-- this size is available in o(n)
length :: String -> CountOf Char
length :: String -> CountOf Char
length (String UArray Word8
arr)
    | Offset Word8
start Offset Word8 -> Offset Word8 -> Bool
forall a. Eq a => a -> a -> Bool
== Offset Word8
end = CountOf Char
0
    | Bool
otherwise    = (Block Word8 -> CountOf Char)
-> (FinalPtr Word8 -> Ptr Word8 -> ST Any (CountOf Char))
-> UArray Word8
-> CountOf Char
forall ty a s.
(Block ty -> a)
-> (FinalPtr ty -> Ptr ty -> ST s a) -> UArray ty -> a
C.onBackend Block Word8 -> CountOf Char
goVec (\FinalPtr Word8
_ -> CountOf Char -> ST Any (CountOf Char)
forall (f :: * -> *) a. Applicative f => a -> f a
pure (CountOf Char -> ST Any (CountOf Char))
-> (Ptr Word8 -> CountOf Char)
-> Ptr Word8
-> ST Any (CountOf Char)
forall k (cat :: k -> k -> *) (b :: k) (c :: k) (a :: k).
Category cat =>
cat b c -> cat a b -> cat a c
. Ptr Word8 -> CountOf Char
goAddr) UArray Word8
arr
  where
    (C.ValidRange !Offset Word8
start !Offset Word8
end) = UArray Word8 -> ValidRange Word8
forall ty. UArray ty -> ValidRange ty
offsetsValidRange UArray Word8
arr
    goVec :: Block Word8 -> CountOf Char
goVec Block Word8
ma = Block Word8 -> Offset Word8 -> Offset Word8 -> CountOf Char
forall container.
(Indexable container Word8, Indexable container Word64) =>
container -> Offset Word8 -> Offset Word8 -> CountOf Char
UTF8.length Block Word8
ma Offset Word8
start Offset Word8
end
    goAddr :: Ptr Word8 -> CountOf Char
goAddr Ptr Word8
ptr = Ptr Word8 -> Offset Word8 -> Offset Word8 -> CountOf Char
forall container.
(Indexable container Word8, Indexable container Word64) =>
container -> Offset Word8 -> Offset Word8 -> CountOf Char
UTF8.length Ptr Word8
ptr Offset Word8
start Offset Word8
end

-- | Replicate a character @c@ @n@ times to create a string of length @n@
replicate :: CountOf Char -> Char -> String
replicate :: CountOf Char -> Char -> String
replicate (CountOf Int
n) Char
c = (forall s. ST s String) -> String
forall a. (forall s. ST s a) -> a
runST (CountOf Word8 -> ST s (MutableString (PrimState (ST s)))
forall (prim :: * -> *).
PrimMonad prim =>
CountOf Word8 -> prim (MutableString (PrimState prim))
new CountOf Word8
nbBytes ST s (MutableString s)
-> (MutableString s -> ST s String) -> ST s String
forall (m :: * -> *) a b. Monad m => m a -> (a -> m b) -> m b
>>= MutableString s -> ST s String
forall (prim :: * -> *).
PrimMonad prim =>
MutableString (PrimState prim) -> prim String
fill)
  where
    nbBytes :: CountOf Word8
nbBytes   = Word -> CountOf Word8 -> CountOf Word8
forall a n. (Additive a, IsNatural n) => n -> a -> a
scale (Int -> Word
forall source destination.
Cast source destination =>
source -> destination
cast Int
n :: Word) CountOf Word8
sz
    sz :: CountOf Word8
sz = Int -> CountOf Word8
charToBytes (Char -> Int
forall a. Enum a => a -> Int
fromEnum Char
c)
    fill :: PrimMonad prim => MutableString (PrimState prim) -> prim String
    fill :: MutableString (PrimState prim) -> prim String
fill MutableString (PrimState prim)
ms = Offset Word8 -> prim String
loop (Int -> Offset Word8
forall ty. Int -> Offset ty
Offset Int
0)
      where
        loop :: Offset Word8 -> prim String
loop Offset Word8
idx
            | Offset Word8
idx Offset Word8 -> CountOf Word8 -> Bool
forall ty. Offset ty -> CountOf ty -> Bool
.==# CountOf Word8
nbBytes = MutableString (PrimState prim) -> prim String
forall (prim :: * -> *).
PrimMonad prim =>
MutableString (PrimState prim) -> prim String
freeze MutableString (PrimState prim)
ms
            | Bool
otherwise        = MutableString (PrimState prim)
-> Offset Word8 -> Char -> prim (Offset Word8)
forall (prim :: * -> *).
PrimMonad prim =>
MutableString (PrimState prim)
-> Offset Word8 -> Char -> prim (Offset Word8)
write MutableString (PrimState prim)
ms Offset Word8
idx Char
c prim (Offset Word8) -> (Offset Word8 -> prim String) -> prim String
forall (m :: * -> *) a b. Monad m => m a -> (a -> m b) -> m b
>>= Offset Word8 -> prim String
loop

-- | Copy the String
--
-- The slice of memory is copied to a new slice, making the new string
-- independent from the original string..
copy :: String -> String
copy :: String -> String
copy (String UArray Word8
s) = UArray Word8 -> String
String (UArray Word8 -> UArray Word8
forall ty. PrimType ty => UArray ty -> UArray ty
Vec.copy UArray Word8
s)

-- | Create a single element String
singleton :: Char -> String
singleton :: Char -> String
singleton Char
c = (forall s. ST s String) -> String
forall a. (forall s. ST s a) -> a
runST ((forall s. ST s String) -> String)
-> (forall s. ST s String) -> String
forall a b. (a -> b) -> a -> b
$ do
    MutableString s
ms <- CountOf Word8 -> ST s (MutableString (PrimState (ST s)))
forall (prim :: * -> *).
PrimMonad prim =>
CountOf Word8 -> prim (MutableString (PrimState prim))
new CountOf Word8
nbBytes
    Offset Word8
_  <- MutableString (PrimState (ST s))
-> Offset Word8 -> Char -> ST s (Offset Word8)
forall (prim :: * -> *).
PrimMonad prim =>
MutableString (PrimState prim)
-> Offset Word8 -> Char -> prim (Offset Word8)
write MutableString s
MutableString (PrimState (ST s))
ms (Int -> Offset Word8
forall ty. Int -> Offset ty
Offset Int
0) Char
c
    MutableString (PrimState (ST s)) -> ST s String
forall (prim :: * -> *).
PrimMonad prim =>
MutableString (PrimState prim) -> prim String
freeze MutableString s
MutableString (PrimState (ST s))
ms
  where
    !nbBytes :: CountOf Word8
nbBytes = Int -> CountOf Word8
charToBytes (Char -> Int
forall a. Enum a => a -> Int
fromEnum Char
c)

-- | Unsafely create a string of up to @sz@ bytes.
--
-- The callback @f@ needs to return the number of bytes filled in the underlaying
-- bytes buffer. No check is made on the callback return values, and if it's not
-- contained without the bounds, bad things will happen.
create :: PrimMonad prim => CountOf Word8 -> (MutableString (PrimState prim) -> prim (Offset Word8)) -> prim String
create :: CountOf Word8
-> (MutableString (PrimState prim) -> prim (Offset Word8))
-> prim String
create CountOf Word8
sz MutableString (PrimState prim) -> prim (Offset Word8)
f = do
    MutableString (PrimState prim)
ms     <- CountOf Word8 -> prim (MutableString (PrimState prim))
forall (prim :: * -> *).
PrimMonad prim =>
CountOf Word8 -> prim (MutableString (PrimState prim))
new CountOf Word8
sz
    Offset Word8
filled <- MutableString (PrimState prim) -> prim (Offset Word8)
f MutableString (PrimState prim)
ms
    if Offset Word8
filled Offset Word8 -> CountOf Word8 -> Bool
forall ty. Offset ty -> CountOf ty -> Bool
.==# CountOf Word8
sz
        then MutableString (PrimState prim) -> prim String
forall (prim :: * -> *).
PrimMonad prim =>
MutableString (PrimState prim) -> prim String
freeze MutableString (PrimState prim)
ms
        else do
            String
s <- MutableString (PrimState prim) -> prim String
forall (prim :: * -> *).
PrimMonad prim =>
MutableString (PrimState prim) -> prim String
freeze MutableString (PrimState prim)
ms
            let (String UArray Word8
ba) = String
s
            String -> prim String
forall (f :: * -> *) a. Applicative f => a -> f a
pure (String -> prim String) -> String -> prim String
forall a b. (a -> b) -> a -> b
$ UArray Word8 -> String
String (UArray Word8 -> String) -> UArray Word8 -> String
forall a b. (a -> b) -> a -> b
$ CountOf Word8 -> UArray Word8 -> UArray Word8
forall ty. CountOf ty -> UArray ty -> UArray ty
C.take (Offset Word8 -> CountOf Word8
forall a. Offset a -> CountOf a
offsetAsSize Offset Word8
filled) UArray Word8
ba

-- | Monomorphically map the character in a string and return the transformed one
charMap :: (Char -> Char) -> String -> String
charMap :: (Char -> Char) -> String -> String
charMap Char -> Char
f String
src
    | CountOf Word8
srcSz CountOf Word8 -> CountOf Word8 -> Bool
forall a. Eq a => a -> a -> Bool
== CountOf Word8
0 = String
forall a. Monoid a => a
mempty
    | Bool
otherwise  =
        let !([(String, CountOf Word8)]
elems, CountOf Word8
nbBytes) = [(String, CountOf Word8)]
-> Offset Word8
-> CountOf Word8
-> ([(String, CountOf Word8)], CountOf Word8)
allocateAndFill [] (Int -> Offset Word8
forall ty. Int -> Offset ty
Offset Int
0) (Int -> CountOf Word8
forall ty. Int -> CountOf ty
CountOf Int
0)
         in (forall s. ST s String) -> String
forall a. (forall s. ST s a) -> a
runST ((forall s. ST s String) -> String)
-> (forall s. ST s String) -> String
forall a b. (a -> b) -> a -> b
$ do
                MutableString s
dest <- CountOf Word8 -> ST s (MutableString (PrimState (ST s)))
forall (prim :: * -> *).
PrimMonad prim =>
CountOf Word8 -> prim (MutableString (PrimState prim))
new CountOf Word8
nbBytes
                MutableString (PrimState (ST s))
-> [(String, CountOf Word8)] -> Offset Word8 -> ST s ()
forall (m :: * -> *).
PrimMonad m =>
MutableString (PrimState m)
-> [(String, CountOf Word8)] -> Offset Word8 -> m ()
copyLoop MutableString s
MutableString (PrimState (ST s))
dest [(String, CountOf Word8)]
elems (Int -> Offset Word8
forall ty. Int -> Offset ty
Offset Int
0 Offset Word8 -> CountOf Word8 -> Offset Word8
forall ty. Offset ty -> CountOf ty -> Offset ty
`offsetPlusE` CountOf Word8
nbBytes)
                MutableString (PrimState (ST s)) -> ST s String
forall (prim :: * -> *).
PrimMonad prim =>
MutableString (PrimState prim) -> prim String
freeze MutableString s
MutableString (PrimState (ST s))
dest
  where
    !srcSz :: CountOf Word8
srcSz = String -> CountOf Word8
size String
src
    srcEnd :: Offset Word8
srcEnd = Offset Word8
forall a. Additive a => a
azero Offset Word8 -> CountOf Word8 -> Offset Word8
forall ty. Offset ty -> CountOf ty -> Offset ty
`offsetPlusE` CountOf Word8
srcSz

    allocateAndFill :: [(String, CountOf Word8)]
                    -> Offset8
                    -> CountOf Word8
                    -> ([(String,CountOf Word8)], CountOf Word8)
    allocateAndFill :: [(String, CountOf Word8)]
-> Offset Word8
-> CountOf Word8
-> ([(String, CountOf Word8)], CountOf Word8)
allocateAndFill [(String, CountOf Word8)]
acc Offset Word8
idx CountOf Word8
bytesWritten
        | Offset Word8
idx Offset Word8 -> Offset Word8 -> Bool
forall a. Eq a => a -> a -> Bool
== Offset Word8
srcEnd = ([(String, CountOf Word8)]
acc, CountOf Word8
bytesWritten)
        | Bool
otherwise     =
            let (el :: (String, CountOf Word8)
el@(String
_,CountOf Word8
addBytes), Offset Word8
idx') = (forall s. ST s ((String, CountOf Word8), Offset Word8))
-> ((String, CountOf Word8), Offset Word8)
forall a. (forall s. ST s a) -> a
runST ((forall s. ST s ((String, CountOf Word8), Offset Word8))
 -> ((String, CountOf Word8), Offset Word8))
-> (forall s. ST s ((String, CountOf Word8), Offset Word8))
-> ((String, CountOf Word8), Offset Word8)
forall a b. (a -> b) -> a -> b
$ do
                    -- make sure we allocate at least 4 bytes for the destination for the last few bytes
                    -- otherwise allocating less would bring the danger of spinning endlessly
                    -- and never succeeding.
                    let !diffBytes :: Difference (Offset Word8)
diffBytes = Offset Word8
srcEnd Offset Word8 -> Offset Word8 -> Difference (Offset Word8)
forall a. Subtractive a => a -> a -> Difference a
- Offset Word8
idx
                        !allocatedBytes :: CountOf Word8
allocatedBytes = if Difference (Offset Word8)
CountOf Word8
diffBytes CountOf Word8 -> CountOf Word8 -> Bool
forall a. Ord a => a -> a -> Bool
<= Int -> CountOf Word8
forall ty. Int -> CountOf ty
CountOf Int
4 then Int -> CountOf Word8
forall ty. Int -> CountOf ty
CountOf Int
4 else Difference (Offset Word8)
CountOf Word8
diffBytes
                    MutableString s
ms <- CountOf Word8 -> ST s (MutableString (PrimState (ST s)))
forall (prim :: * -> *).
PrimMonad prim =>
CountOf Word8 -> prim (MutableString (PrimState prim))
new CountOf Word8
allocatedBytes
                    (CountOf Word8
dstIdx, Offset Word8
srcIdx) <- MutableString (PrimState (ST s))
-> CountOf Word8
-> Offset Word8
-> ST s (CountOf Word8, Offset Word8)
forall (prim :: * -> *).
PrimMonad prim =>
MutableString (PrimState prim)
-> CountOf Word8
-> Offset Word8
-> prim (CountOf Word8, Offset Word8)
fill MutableString s
MutableString (PrimState (ST s))
ms CountOf Word8
allocatedBytes Offset Word8
idx
                    String
s <- MutableString (PrimState (ST s)) -> ST s String
forall (prim :: * -> *).
PrimMonad prim =>
MutableString (PrimState prim) -> prim String
freeze MutableString s
MutableString (PrimState (ST s))
ms
                    ((String, CountOf Word8), Offset Word8)
-> ST s ((String, CountOf Word8), Offset Word8)
forall (m :: * -> *) a. Monad m => a -> m a
return ((String
s, CountOf Word8
dstIdx), Offset Word8
srcIdx)
             in [(String, CountOf Word8)]
-> Offset Word8
-> CountOf Word8
-> ([(String, CountOf Word8)], CountOf Word8)
allocateAndFill ((String, CountOf Word8)
el (String, CountOf Word8)
-> [(String, CountOf Word8)] -> [(String, CountOf Word8)]
forall a. a -> [a] -> [a]
: [(String, CountOf Word8)]
acc) Offset Word8
idx' (CountOf Word8
bytesWritten CountOf Word8 -> CountOf Word8 -> CountOf Word8
forall a. Additive a => a -> a -> a
+ CountOf Word8
addBytes)

    fill :: PrimMonad prim
         => MutableString (PrimState prim)
         -> CountOf Word8
         -> Offset8
         -> prim (CountOf Word8, Offset8)
    fill :: MutableString (PrimState prim)
-> CountOf Word8
-> Offset Word8
-> prim (CountOf Word8, Offset Word8)
fill MutableString (PrimState prim)
mba CountOf Word8
dsz Offset Word8
srcIdxOrig =
        Offset Word8 -> Offset Word8 -> prim (CountOf Word8, Offset Word8)
loop (Int -> Offset Word8
forall ty. Int -> Offset ty
Offset Int
0) Offset Word8
srcIdxOrig
      where
        endDst :: Offset Word8
endDst = (Int -> Offset Word8
forall ty. Int -> Offset ty
Offset Int
0) Offset Word8 -> CountOf Word8 -> Offset Word8
forall ty. Offset ty -> CountOf ty -> Offset ty
`offsetPlusE` CountOf Word8
dsz
        loop :: Offset Word8 -> Offset Word8 -> prim (CountOf Word8, Offset Word8)
loop Offset Word8
dstIdx Offset Word8
srcIdx
            | Offset Word8
srcIdx Offset Word8 -> Offset Word8 -> Bool
forall a. Eq a => a -> a -> Bool
== Offset Word8
srcEnd = (CountOf Word8, Offset Word8) -> prim (CountOf Word8, Offset Word8)
forall (m :: * -> *) a. Monad m => a -> m a
return (Offset Word8 -> CountOf Word8
forall a. Offset a -> CountOf a
offsetAsSize Offset Word8
dstIdx, Offset Word8
srcIdx)
            | Offset Word8
dstIdx Offset Word8 -> Offset Word8 -> Bool
forall a. Eq a => a -> a -> Bool
== Offset Word8
endDst = (CountOf Word8, Offset Word8) -> prim (CountOf Word8, Offset Word8)
forall (m :: * -> *) a. Monad m => a -> m a
return (Offset Word8 -> CountOf Word8
forall a. Offset a -> CountOf a
offsetAsSize Offset Word8
dstIdx, Offset Word8
srcIdx)
            | Bool
otherwise        =
                let !(Step Char
c Offset Word8
srcIdx') = String -> Offset Word8 -> Step
next String
src Offset Word8
srcIdx
                    c' :: Char
c' = Char -> Char
f Char
c -- the mapped char
                    !nbBytes :: CountOf Word8
nbBytes = Int -> CountOf Word8
charToBytes (Char -> Int
forall a. Enum a => a -> Int
fromEnum Char
c')
                 in -- check if we have room in the destination buffer
                    if Offset Word8
dstIdx Offset Word8 -> CountOf Word8 -> Offset Word8
forall ty. Offset ty -> CountOf ty -> Offset ty
`offsetPlusE` CountOf Word8
nbBytes Offset Word8 -> Offset Word8 -> Bool
forall a. Ord a => a -> a -> Bool
<= CountOf Word8 -> Offset Word8
forall a. CountOf a -> Offset a
sizeAsOffset CountOf Word8
dsz
                        then do Offset Word8
dstIdx' <- MutableString (PrimState prim)
-> Offset Word8 -> Char -> prim (Offset Word8)
forall (prim :: * -> *).
PrimMonad prim =>
MutableString (PrimState prim)
-> Offset Word8 -> Char -> prim (Offset Word8)
write MutableString (PrimState prim)
mba Offset Word8
dstIdx Char
c'
                                Offset Word8 -> Offset Word8 -> prim (CountOf Word8, Offset Word8)
loop Offset Word8
dstIdx' Offset Word8
srcIdx'
                        else (CountOf Word8, Offset Word8) -> prim (CountOf Word8, Offset Word8)
forall (m :: * -> *) a. Monad m => a -> m a
return (Offset Word8 -> CountOf Word8
forall a. Offset a -> CountOf a
offsetAsSize Offset Word8
dstIdx, Offset Word8
srcIdx)

    copyLoop :: MutableString (PrimState m)
-> [(String, CountOf Word8)] -> Offset Word8 -> m ()
copyLoop MutableString (PrimState m)
_   []     (Offset Int
0) = () -> m ()
forall (m :: * -> *) a. Monad m => a -> m a
return ()
    copyLoop MutableString (PrimState m)
_   []     Offset Word8
n          = [Char] -> m ()
forall a. HasCallStack => [Char] -> a
error ([Char]
"charMap invalid: " [Char] -> [Char] -> [Char]
forall a. Semigroup a => a -> a -> a
<> Offset Word8 -> [Char]
forall a. Show a => a -> [Char]
show Offset Word8
n)
    copyLoop ms :: MutableString (PrimState m)
ms@(MutableString MUArray Word8 (PrimState m)
mba) ((String UArray Word8
ba, CountOf Word8
sz):[(String, CountOf Word8)]
xs) Offset Word8
end = do
        let start :: Offset Word8
start = Offset Word8
end Offset Word8 -> CountOf Word8 -> Offset Word8
forall ty. Offset ty -> CountOf ty -> Offset ty
`offsetMinusE` CountOf Word8
sz
        MUArray Word8 (PrimState m)
-> Offset Word8
-> UArray Word8
-> Offset Word8
-> CountOf Word8
-> m ()
forall (prim :: * -> *) ty.
(PrimMonad prim, PrimType ty) =>
MUArray ty (PrimState prim)
-> Offset ty -> UArray ty -> Offset ty -> CountOf ty -> prim ()
Vec.unsafeCopyAtRO MUArray Word8 (PrimState m)
mba Offset Word8
start UArray Word8
ba (Int -> Offset Word8
forall ty. Int -> Offset ty
Offset Int
0) CountOf Word8
sz
        MutableString (PrimState m)
-> [(String, CountOf Word8)] -> Offset Word8 -> m ()
copyLoop MutableString (PrimState m)
ms [(String, CountOf Word8)]
xs Offset Word8
start

-- | Append a Char to the end of the String and return this new String
snoc :: String -> Char -> String
snoc :: String -> Char -> String
snoc s :: String
s@(String UArray Word8
ba) Char
c
    | CountOf Word8
len CountOf Word8 -> CountOf Word8 -> Bool
forall a. Eq a => a -> a -> Bool
== Int -> CountOf Word8
forall ty. Int -> CountOf ty
CountOf Int
0 = Char -> String
singleton Char
c
    | Bool
otherwise     = (forall s. ST s String) -> String
forall a. (forall s. ST s a) -> a
runST ((forall s. ST s String) -> String)
-> (forall s. ST s String) -> String
forall a b. (a -> b) -> a -> b
$ do
        MutableString s
ms <- CountOf Word8 -> ST s (MutableString (PrimState (ST s)))
forall (prim :: * -> *).
PrimMonad prim =>
CountOf Word8 -> prim (MutableString (PrimState prim))
new (CountOf Word8
len CountOf Word8 -> CountOf Word8 -> CountOf Word8
forall a. Additive a => a -> a -> a
+ CountOf Word8
nbBytes)
        let (MutableString MUArray Word8 s
mba) = MutableString s
ms
        MUArray Word8 (PrimState (ST s))
-> Offset Word8
-> UArray Word8
-> Offset Word8
-> CountOf Word8
-> ST s ()
forall (prim :: * -> *) ty.
(PrimMonad prim, PrimType ty) =>
MUArray ty (PrimState prim)
-> Offset ty -> UArray ty -> Offset ty -> CountOf ty -> prim ()
Vec.unsafeCopyAtRO MUArray Word8 s
MUArray Word8 (PrimState (ST s))
mba (Int -> Offset Word8
forall ty. Int -> Offset ty
Offset Int
0) UArray Word8
ba (Int -> Offset Word8
forall ty. Int -> Offset ty
Offset Int
0) CountOf Word8
len
        Offset Word8
_ <- MutableString (PrimState (ST s))
-> Offset Word8 -> Char -> ST s (Offset Word8)
forall (prim :: * -> *).
PrimMonad prim =>
MutableString (PrimState prim)
-> Offset Word8 -> Char -> prim (Offset Word8)
write MutableString s
MutableString (PrimState (ST s))
ms (Offset Word8
forall a. Additive a => a
azero Offset Word8 -> CountOf Word8 -> Offset Word8
forall ty. Offset ty -> CountOf ty -> Offset ty
`offsetPlusE` CountOf Word8
len) Char
c
        MutableString (PrimState (ST s)) -> ST s String
forall (prim :: * -> *).
PrimMonad prim =>
MutableString (PrimState prim) -> prim String
freeze MutableString s
MutableString (PrimState (ST s))
ms
  where
    !len :: CountOf Word8
len     = String -> CountOf Word8
size String
s
    !nbBytes :: CountOf Word8
nbBytes = Int -> CountOf Word8
charToBytes (Char -> Int
forall a. Enum a => a -> Int
fromEnum Char
c)

-- | Prepend a Char to the beginning of the String and return this new String
cons :: Char -> String -> String
cons :: Char -> String -> String
cons Char
c s :: String
s@(String UArray Word8
ba)
  | CountOf Word8
len CountOf Word8 -> CountOf Word8 -> Bool
forall a. Eq a => a -> a -> Bool
== Int -> CountOf Word8
forall ty. Int -> CountOf ty
CountOf Int
0 = Char -> String
singleton Char
c
  | Bool
otherwise     = (forall s. ST s String) -> String
forall a. (forall s. ST s a) -> a
runST ((forall s. ST s String) -> String)
-> (forall s. ST s String) -> String
forall a b. (a -> b) -> a -> b
$ do
      MutableString s
ms <- CountOf Word8 -> ST s (MutableString (PrimState (ST s)))
forall (prim :: * -> *).
PrimMonad prim =>
CountOf Word8 -> prim (MutableString (PrimState prim))
new (CountOf Word8
len CountOf Word8 -> CountOf Word8 -> CountOf Word8
forall a. Additive a => a -> a -> a
+ CountOf Word8
nbBytes)
      let (MutableString MUArray Word8 s
mba) = MutableString s
ms
      Offset Word8
idx <- MutableString (PrimState (ST s))
-> Offset Word8 -> Char -> ST s (Offset Word8)
forall (prim :: * -> *).
PrimMonad prim =>
MutableString (PrimState prim)
-> Offset Word8 -> Char -> prim (Offset Word8)
write MutableString s
MutableString (PrimState (ST s))
ms (Int -> Offset Word8
forall ty. Int -> Offset ty
Offset Int
0) Char
c
      MUArray Word8 (PrimState (ST s))
-> Offset Word8
-> UArray Word8
-> Offset Word8
-> CountOf Word8
-> ST s ()
forall (prim :: * -> *) ty.
(PrimMonad prim, PrimType ty) =>
MUArray ty (PrimState prim)
-> Offset ty -> UArray ty -> Offset ty -> CountOf ty -> prim ()
Vec.unsafeCopyAtRO MUArray Word8 s
MUArray Word8 (PrimState (ST s))
mba Offset Word8
idx UArray Word8
ba (Int -> Offset Word8
forall ty. Int -> Offset ty
Offset Int
0) CountOf Word8
len
      MutableString (PrimState (ST s)) -> ST s String
forall (prim :: * -> *).
PrimMonad prim =>
MutableString (PrimState prim) -> prim String
freeze MutableString s
MutableString (PrimState (ST s))
ms
  where
    !len :: CountOf Word8
len     = String -> CountOf Word8
size String
s
    !nbBytes :: CountOf Word8
nbBytes = Int -> CountOf Word8
charToBytes (Char -> Int
forall a. Enum a => a -> Int
fromEnum Char
c)

-- | Extract the String stripped of the last character and the last character if not empty
--
-- If empty, Nothing is returned
unsnoc :: String -> Maybe (String, Char)
unsnoc :: String -> Maybe (String, Char)
unsnoc s :: String
s@(String UArray Word8
arr)
    | CountOf Word8
sz CountOf Word8 -> CountOf Word8 -> Bool
forall a. Eq a => a -> a -> Bool
== CountOf Word8
0   = Maybe (String, Char)
forall a. Maybe a
Nothing
    | Bool
otherwise =
        let !(StepBack Char
c Offset Word8
idx) = String -> Offset Word8 -> StepBack
prev String
s (CountOf Word8 -> Offset Word8
forall a. CountOf a -> Offset a
sizeAsOffset CountOf Word8
sz)
         in (String, Char) -> Maybe (String, Char)
forall a. a -> Maybe a
Just (UArray Word8 -> String
String (UArray Word8 -> String) -> UArray Word8 -> String
forall a b. (a -> b) -> a -> b
$ CountOf Word8 -> UArray Word8 -> UArray Word8
forall ty. CountOf ty -> UArray ty -> UArray ty
Vec.take (Offset Word8 -> CountOf Word8
forall a. Offset a -> CountOf a
offsetAsSize Offset Word8
idx) UArray Word8
arr, Char
c)
  where
    sz :: CountOf Word8
sz = String -> CountOf Word8
size String
s

-- | Extract the First character of a string, and the String stripped of the first character.
--
-- If empty, Nothing is returned
uncons :: String -> Maybe (Char, String)
uncons :: String -> Maybe (Char, String)
uncons s :: String
s@(String UArray Word8
ba)
    | String -> Bool
null String
s    = Maybe (Char, String)
forall a. Maybe a
Nothing
    | Bool
otherwise =
        let !(Step Char
c Offset Word8
idx) = String -> Offset Word8 -> Step
next String
s Offset Word8
forall a. Additive a => a
azero
         in (Char, String) -> Maybe (Char, String)
forall a. a -> Maybe a
Just (Char
c, UArray Word8 -> String
String (UArray Word8 -> String) -> UArray Word8 -> String
forall a b. (a -> b) -> a -> b
$ CountOf Word8 -> UArray Word8 -> UArray Word8
forall ty. CountOf ty -> UArray ty -> UArray ty
Vec.drop (Offset Word8 -> CountOf Word8
forall a. Offset a -> CountOf a
offsetAsSize Offset Word8
idx) UArray Word8
ba)

-- | Look for a predicate in the String and return the matched character, if any.
find :: (Char -> Bool) -> String -> Maybe Char
find :: (Char -> Bool) -> String -> Maybe Char
find Char -> Bool
predicate String
s = Offset Word8 -> Maybe Char
loop (Int -> Offset Word8
forall ty. Int -> Offset ty
Offset Int
0)
  where
    !sz :: CountOf Word8
sz = String -> CountOf Word8
size String
s
    end :: Offset Word8
end = Int -> Offset Word8
forall ty. Int -> Offset ty
Offset Int
0 Offset Word8 -> CountOf Word8 -> Offset Word8
forall ty. Offset ty -> CountOf ty -> Offset ty
`offsetPlusE` CountOf Word8
sz
    loop :: Offset Word8 -> Maybe Char
loop Offset Word8
idx
        | Offset Word8
idx Offset Word8 -> Offset Word8 -> Bool
forall a. Eq a => a -> a -> Bool
== Offset Word8
end = Maybe Char
forall a. Maybe a
Nothing
        | Bool
otherwise =
            let !(Step Char
c Offset Word8
idx') = String -> Offset Word8 -> Step
next String
s Offset Word8
idx
             in case Char -> Bool
predicate Char
c of
                    Bool
True  -> Char -> Maybe Char
forall a. a -> Maybe a
Just Char
c
                    Bool
False -> Offset Word8 -> Maybe Char
loop Offset Word8
idx'

-- | Sort the character in a String using a specific sort function
--
-- TODO: optimise not going through a list
sortBy :: (Char -> Char -> Ordering) -> String -> String
sortBy :: (Char -> Char -> Ordering) -> String -> String
sortBy Char -> Char -> Ordering
sortF String
s = [Item String] -> String
forall l. IsList l => [Item l] -> l
fromList ([Item String] -> String) -> [Item String] -> String
forall a b. (a -> b) -> a -> b
$ (Char -> Char -> Ordering) -> [Char] -> [Char]
forall a. (a -> a -> Ordering) -> [a] -> [a]
Data.List.sortBy Char -> Char -> Ordering
sortF ([Char] -> [Char]) -> [Char] -> [Char]
forall a b. (a -> b) -> a -> b
$ String -> [Item String]
forall l. IsList l => l -> [Item l]
toList String
s -- FIXME for tests

-- | Filter characters of a string using the predicate
filter :: (Char -> Bool) -> String -> String
filter :: (Char -> Bool) -> String -> String
filter Char -> Bool
predicate (String UArray Word8
arr) = (forall s. ST s String) -> String
forall a. (forall s. ST s a) -> a
runST ((forall s. ST s String) -> String)
-> (forall s. ST s String) -> String
forall a b. (a -> b) -> a -> b
$ do
    (CountOf Word8
finalSize, MutableString s
dst) <- CountOf Word8
-> (MutableBlock Word8 (PrimState (ST s)) -> ST s (CountOf Word8))
-> ST s (CountOf Word8, MutableString (PrimState (ST s)))
forall (prim :: * -> *) a.
PrimMonad prim =>
CountOf Word8
-> (MutableBlock Word8 (PrimState prim) -> prim a)
-> prim (a, MutableString (PrimState prim))
newNative CountOf Word8
sz ((MutableBlock Word8 (PrimState (ST s)) -> ST s (CountOf Word8))
 -> ST s (CountOf Word8, MutableString (PrimState (ST s))))
-> (MutableBlock Word8 (PrimState (ST s)) -> ST s (CountOf Word8))
-> ST s (CountOf Word8, MutableString (PrimState (ST s)))
forall a b. (a -> b) -> a -> b
$ \(MutableBlock MutableByteArray# (PrimState (ST s))
mba) ->
        (Block Word8 -> ST s (CountOf Word8))
-> (FinalPtr Word8 -> ST s (CountOf Word8))
-> UArray Word8
-> ST s (CountOf Word8)
forall (prim :: * -> *) ty a.
PrimMonad prim =>
(Block ty -> prim a)
-> (FinalPtr ty -> prim a) -> UArray ty -> prim a
C.onBackendPrim (\ba :: Block Word8
ba@(Block !ByteArray#
_) -> (Char -> Bool)
-> CountOf Word8
-> MutableByteArray# s
-> Block Word8
-> Offset Word8
-> ST s (CountOf Word8)
forall s container.
Indexable container Word8 =>
(Char -> Bool)
-> CountOf Word8
-> MutableByteArray# s
-> container
-> Offset Word8
-> ST s (CountOf Word8)
Alg.copyFilter Char -> Bool
predicate CountOf Word8
sz MutableByteArray# s
MutableByteArray# (PrimState (ST s))
mba Block Word8
ba Offset Word8
start)
                        (\FinalPtr Word8
fptr -> FinalPtr Word8
-> (Ptr Word8 -> ST s (CountOf Word8)) -> ST s (CountOf Word8)
forall (prim :: * -> *) p a.
PrimMonad prim =>
FinalPtr p -> (Ptr p -> prim a) -> prim a
withFinalPtr FinalPtr Word8
fptr ((Ptr Word8 -> ST s (CountOf Word8)) -> ST s (CountOf Word8))
-> (Ptr Word8 -> ST s (CountOf Word8)) -> ST s (CountOf Word8)
forall a b. (a -> b) -> a -> b
$ \ptr :: Ptr Word8
ptr@(Ptr !Addr#
_) -> (Char -> Bool)
-> CountOf Word8
-> MutableByteArray# s
-> Ptr Word8
-> Offset Word8
-> ST s (CountOf Word8)
forall s container.
Indexable container Word8 =>
(Char -> Bool)
-> CountOf Word8
-> MutableByteArray# s
-> container
-> Offset Word8
-> ST s (CountOf Word8)
Alg.copyFilter Char -> Bool
predicate CountOf Word8
sz MutableByteArray# s
MutableByteArray# (PrimState (ST s))
mba Ptr Word8
ptr Offset Word8
start)
                        UArray Word8
arr
    CountOf Word8 -> MutableString (PrimState (ST s)) -> ST s String
forall (prim :: * -> *).
PrimMonad prim =>
CountOf Word8 -> MutableString (PrimState prim) -> prim String
freezeShrink CountOf Word8
finalSize MutableString s
MutableString (PrimState (ST s))
dst
  where
    !sz :: CountOf Word8
sz    = UArray Word8 -> CountOf Word8
forall ty. UArray ty -> CountOf ty
C.length UArray Word8
arr
    !start :: Offset Word8
start = UArray Word8 -> Offset Word8
forall ty. UArray ty -> Offset ty
C.offset UArray Word8
arr

-- | Reverse a string
reverse :: String -> String
reverse :: String -> String
reverse (String UArray Word8
arr) = (forall s. ST s String) -> String
forall a. (forall s. ST s a) -> a
runST ((forall s. ST s String) -> String)
-> (forall s. ST s String) -> String
forall a b. (a -> b) -> a -> b
$ do
    MutableString s
s <- CountOf Word8
-> (MutableBlock Word8 (PrimState (ST s)) -> ST s ())
-> ST s (MutableString (PrimState (ST s)))
forall (prim :: * -> *).
PrimMonad prim =>
CountOf Word8
-> (MutableBlock Word8 (PrimState prim) -> prim ())
-> prim (MutableString (PrimState prim))
newNative_ (UArray Word8 -> CountOf Word8
forall ty. UArray ty -> CountOf ty
C.length UArray Word8
arr) ((MutableBlock Word8 (PrimState (ST s)) -> ST s ())
 -> ST s (MutableString (PrimState (ST s))))
-> (MutableBlock Word8 (PrimState (ST s)) -> ST s ())
-> ST s (MutableString (PrimState (ST s)))
forall a b. (a -> b) -> a -> b
$ \(MutableBlock MutableByteArray# (PrimState (ST s))
mba) ->
            (Block Word8 -> ST s ())
-> (FinalPtr Word8 -> ST s ()) -> UArray Word8 -> ST s ()
forall (prim :: * -> *) ty a.
PrimMonad prim =>
(Block ty -> prim a)
-> (FinalPtr ty -> prim a) -> UArray ty -> prim a
C.onBackendPrim
                (\ba :: Block Word8
ba@(Block !ByteArray#
_) -> MutableByteArray# (PrimState (ST s))
-> Offset Word8
-> Block Word8
-> Offset Word8
-> Offset Word8
-> ST s ()
forall (prim :: * -> *) container.
(PrimMonad prim, Indexable container Word8) =>
MutableByteArray# (PrimState prim)
-> Offset Word8
-> container
-> Offset Word8
-> Offset Word8
-> prim ()
UTF8.reverse MutableByteArray# (PrimState (ST s))
mba Offset Word8
0 Block Word8
ba Offset Word8
start Offset Word8
end)
                (\FinalPtr Word8
fptr -> FinalPtr Word8 -> (Ptr Word8 -> ST s ()) -> ST s ()
forall (prim :: * -> *) p a.
PrimMonad prim =>
FinalPtr p -> (Ptr p -> prim a) -> prim a
withFinalPtr FinalPtr Word8
fptr ((Ptr Word8 -> ST s ()) -> ST s ())
-> (Ptr Word8 -> ST s ()) -> ST s ()
forall a b. (a -> b) -> a -> b
$ \ptr :: Ptr Word8
ptr@(Ptr !Addr#
_) -> MutableByteArray# (PrimState (ST s))
-> Offset Word8
-> Ptr Word8
-> Offset Word8
-> Offset Word8
-> ST s ()
forall (prim :: * -> *) container.
(PrimMonad prim, Indexable container Word8) =>
MutableByteArray# (PrimState prim)
-> Offset Word8
-> container
-> Offset Word8
-> Offset Word8
-> prim ()
UTF8.reverse MutableByteArray# (PrimState (ST s))
mba Offset Word8
0 Ptr Word8
ptr Offset Word8
start Offset Word8
end)
                UArray Word8
arr
    MutableString (PrimState (ST s)) -> ST s String
forall (prim :: * -> *).
PrimMonad prim =>
MutableString (PrimState prim) -> prim String
freeze MutableString s
MutableString (PrimState (ST s))
s
  where
    !(C.ValidRange Offset Word8
start Offset Word8
end) = UArray Word8 -> ValidRange Word8
forall ty. UArray ty -> ValidRange ty
C.offsetsValidRange UArray Word8
arr

-- | Finds where are the insertion points when we search for a `needle`
-- within an `haystack`.
indices :: String -> String -> [Offset8]
indices :: String -> String -> [Offset Word8]
indices (String UArray Word8
ned) (String UArray Word8
hy) = UArray Word8 -> UArray Word8 -> [Offset Word8]
forall ty. PrimType ty => UArray ty -> UArray ty -> [Offset ty]
Vec.indices UArray Word8
ned UArray Word8
hy

-- | Replace all the occurrencies of `needle` with `replacement` in
-- the `haystack` string.
replace :: String -> String -> String -> String
replace :: String -> String -> String -> String
replace (String UArray Word8
needle) (String UArray Word8
replacement) (String UArray Word8
haystack) =
  UArray Word8 -> String
String (UArray Word8 -> String) -> UArray Word8 -> String
forall a b. (a -> b) -> a -> b
$ UArray Word8 -> UArray Word8 -> UArray Word8 -> UArray Word8
forall ty.
PrimType ty =>
UArray ty -> UArray ty -> UArray ty -> UArray ty
Vec.replace UArray Word8
needle UArray Word8
replacement UArray Word8
haystack

-- | Return the nth character in a String
--
-- Compared to an array, the string need to be scanned from the beginning
-- since the UTF8 encoding is variable.
index :: String -> Offset Char -> Maybe Char
index :: String -> Offset Char -> Maybe Char
index String
s Offset Char
n
    | Offset Word8
ofs Offset Word8 -> Offset Word8 -> Bool
forall a. Ord a => a -> a -> Bool
>= Offset Word8
end = Maybe Char
forall a. Maybe a
Nothing
    | Bool
otherwise  =
        let (Step !Char
c Offset Word8
_) = String -> Offset Word8 -> Step
next String
s Offset Word8
ofs
         in Char -> Maybe Char
forall a. a -> Maybe a
Just Char
c
  where
    !nbBytes :: CountOf Word8
nbBytes = String -> CountOf Word8
size String
s
    end :: Offset Word8
end = Offset Word8
0 Offset Word8 -> CountOf Word8 -> Offset Word8
forall ty. Offset ty -> CountOf ty -> Offset ty
`offsetPlusE` CountOf Word8
nbBytes
    ofs :: Offset Word8
ofs = CountOf Char -> String -> Offset Word8
indexN (Offset Char -> CountOf Char
forall a. Offset a -> CountOf a
offsetAsSize Offset Char
n) String
s

-- | Return the index in unit of Char of the first occurence of the predicate returning True
--
-- If not found, Nothing is returned
findIndex :: (Char -> Bool) -> String -> Maybe (Offset Char)
findIndex :: (Char -> Bool) -> String -> Maybe (Offset Char)
findIndex Char -> Bool
predicate String
s = Offset Char -> Offset Word8 -> Maybe (Offset Char)
loop Offset Char
0 Offset Word8
0
  where
    !sz :: CountOf Word8
sz = String -> CountOf Word8
size String
s
    loop :: Offset Char -> Offset Word8 -> Maybe (Offset Char)
loop Offset Char
ofs Offset Word8
idx
        | Offset Word8
idx Offset Word8 -> CountOf Word8 -> Bool
forall ty. Offset ty -> CountOf ty -> Bool
.==# CountOf Word8
sz = Maybe (Offset Char)
forall a. Maybe a
Nothing
        | Bool
otherwise   =
            let !(Step Char
c Offset Word8
idx') = String -> Offset Word8 -> Step
next String
s Offset Word8
idx
             in case Char -> Bool
predicate Char
c of
                    Bool
True  -> Offset Char -> Maybe (Offset Char)
forall a. a -> Maybe a
Just Offset Char
ofs
                    Bool
False -> Offset Char -> Offset Word8 -> Maybe (Offset Char)
loop (Offset Char
ofsOffset Char -> Offset Char -> Offset Char
forall a. Additive a => a -> a -> a
+Offset Char
1) Offset Word8
idx'

-- | Various String Encoding that can be use to convert to and from bytes
data Encoding
    = ASCII7
    | UTF8
    | UTF16
    | UTF32
    | ISO_8859_1
    deriving (Typeable, Typeable Encoding
DataType
Constr
Typeable Encoding
-> (forall (c :: * -> *).
    (forall d b. Data d => c (d -> b) -> d -> c b)
    -> (forall g. g -> c g) -> Encoding -> c Encoding)
-> (forall (c :: * -> *).
    (forall b r. Data b => c (b -> r) -> c r)
    -> (forall r. r -> c r) -> Constr -> c Encoding)
-> (Encoding -> Constr)
-> (Encoding -> DataType)
-> (forall (t :: * -> *) (c :: * -> *).
    Typeable t =>
    (forall d. Data d => c (t d)) -> Maybe (c Encoding))
-> (forall (t :: * -> * -> *) (c :: * -> *).
    Typeable t =>
    (forall d e. (Data d, Data e) => c (t d e)) -> Maybe (c Encoding))
-> ((forall b. Data b => b -> b) -> Encoding -> Encoding)
-> (forall r r'.
    (r -> r' -> r)
    -> r -> (forall d. Data d => d -> r') -> Encoding -> r)
-> (forall r r'.
    (r' -> r -> r)
    -> r -> (forall d. Data d => d -> r') -> Encoding -> r)
-> (forall u. (forall d. Data d => d -> u) -> Encoding -> [u])
-> (forall u. Int -> (forall d. Data d => d -> u) -> Encoding -> u)
-> (forall (m :: * -> *).
    Monad m =>
    (forall d. Data d => d -> m d) -> Encoding -> m Encoding)
-> (forall (m :: * -> *).
    MonadPlus m =>
    (forall d. Data d => d -> m d) -> Encoding -> m Encoding)
-> (forall (m :: * -> *).
    MonadPlus m =>
    (forall d. Data d => d -> m d) -> Encoding -> m Encoding)
-> Data Encoding
Encoding -> DataType
Encoding -> Constr
(forall b. Data b => b -> b) -> Encoding -> Encoding
(forall d b. Data d => c (d -> b) -> d -> c b)
-> (forall g. g -> c g) -> Encoding -> c Encoding
(forall b r. Data b => c (b -> r) -> c r)
-> (forall r. r -> c r) -> Constr -> c Encoding
forall a.
Typeable a
-> (forall (c :: * -> *).
    (forall d b. Data d => c (d -> b) -> d -> c b)
    -> (forall g. g -> c g) -> a -> c a)
-> (forall (c :: * -> *).
    (forall b r. Data b => c (b -> r) -> c r)
    -> (forall r. r -> c r) -> Constr -> c a)
-> (a -> Constr)
-> (a -> DataType)
-> (forall (t :: * -> *) (c :: * -> *).
    Typeable t =>
    (forall d. Data d => c (t d)) -> Maybe (c a))
-> (forall (t :: * -> * -> *) (c :: * -> *).
    Typeable t =>
    (forall d e. (Data d, Data e) => c (t d e)) -> Maybe (c a))
-> ((forall b. Data b => b -> b) -> a -> a)
-> (forall r r'.
    (r -> r' -> r) -> r -> (forall d. Data d => d -> r') -> a -> r)
-> (forall r r'.
    (r' -> r -> r) -> r -> (forall d. Data d => d -> r') -> a -> r)
-> (forall u. (forall d. Data d => d -> u) -> a -> [u])
-> (forall u. Int -> (forall d. Data d => d -> u) -> a -> u)
-> (forall (m :: * -> *).
    Monad m =>
    (forall d. Data d => d -> m d) -> a -> m a)
-> (forall (m :: * -> *).
    MonadPlus m =>
    (forall d. Data d => d -> m d) -> a -> m a)
-> (forall (m :: * -> *).
    MonadPlus m =>
    (forall d. Data d => d -> m d) -> a -> m a)
-> Data a
forall u. Int -> (forall d. Data d => d -> u) -> Encoding -> u
forall u. (forall d. Data d => d -> u) -> Encoding -> [u]
forall r r'.
(r -> r' -> r)
-> r -> (forall d. Data d => d -> r') -> Encoding -> r
forall r r'.
(r' -> r -> r)
-> r -> (forall d. Data d => d -> r') -> Encoding -> r
forall (m :: * -> *).
Monad m =>
(forall d. Data d => d -> m d) -> Encoding -> m Encoding
forall (m :: * -> *).
MonadPlus m =>
(forall d. Data d => d -> m d) -> Encoding -> m Encoding
forall (c :: * -> *).
(forall b r. Data b => c (b -> r) -> c r)
-> (forall r. r -> c r) -> Constr -> c Encoding
forall (c :: * -> *).
(forall d b. Data d => c (d -> b) -> d -> c b)
-> (forall g. g -> c g) -> Encoding -> c Encoding
forall (t :: * -> *) (c :: * -> *).
Typeable t =>
(forall d. Data d => c (t d)) -> Maybe (c Encoding)
forall (t :: * -> * -> *) (c :: * -> *).
Typeable t =>
(forall d e. (Data d, Data e) => c (t d e)) -> Maybe (c Encoding)
$cISO_8859_1 :: Constr
$cUTF32 :: Constr
$cUTF16 :: Constr
$cUTF8 :: Constr
$cASCII7 :: Constr
$tEncoding :: DataType
gmapMo :: (forall d. Data d => d -> m d) -> Encoding -> m Encoding
$cgmapMo :: forall (m :: * -> *).
MonadPlus m =>
(forall d. Data d => d -> m d) -> Encoding -> m Encoding
gmapMp :: (forall d. Data d => d -> m d) -> Encoding -> m Encoding
$cgmapMp :: forall (m :: * -> *).
MonadPlus m =>
(forall d. Data d => d -> m d) -> Encoding -> m Encoding
gmapM :: (forall d. Data d => d -> m d) -> Encoding -> m Encoding
$cgmapM :: forall (m :: * -> *).
Monad m =>
(forall d. Data d => d -> m d) -> Encoding -> m Encoding
gmapQi :: Int -> (forall d. Data d => d -> u) -> Encoding -> u
$cgmapQi :: forall u. Int -> (forall d. Data d => d -> u) -> Encoding -> u
gmapQ :: (forall d. Data d => d -> u) -> Encoding -> [u]
$cgmapQ :: forall u. (forall d. Data d => d -> u) -> Encoding -> [u]
gmapQr :: (r' -> r -> r)
-> r -> (forall d. Data d => d -> r') -> Encoding -> r
$cgmapQr :: forall r r'.
(r' -> r -> r)
-> r -> (forall d. Data d => d -> r') -> Encoding -> r
gmapQl :: (r -> r' -> r)
-> r -> (forall d. Data d => d -> r') -> Encoding -> r
$cgmapQl :: forall r r'.
(r -> r' -> r)
-> r -> (forall d. Data d => d -> r') -> Encoding -> r
gmapT :: (forall b. Data b => b -> b) -> Encoding -> Encoding
$cgmapT :: (forall b. Data b => b -> b) -> Encoding -> Encoding
dataCast2 :: (forall d e. (Data d, Data e) => c (t d e)) -> Maybe (c Encoding)
$cdataCast2 :: forall (t :: * -> * -> *) (c :: * -> *).
Typeable t =>
(forall d e. (Data d, Data e) => c (t d e)) -> Maybe (c Encoding)
dataCast1 :: (forall d. Data d => c (t d)) -> Maybe (c Encoding)
$cdataCast1 :: forall (t :: * -> *) (c :: * -> *).
Typeable t =>
(forall d. Data d => c (t d)) -> Maybe (c Encoding)
dataTypeOf :: Encoding -> DataType
$cdataTypeOf :: Encoding -> DataType
toConstr :: Encoding -> Constr
$ctoConstr :: Encoding -> Constr
gunfold :: (forall b r. Data b => c (b -> r) -> c r)
-> (forall r. r -> c r) -> Constr -> c Encoding
$cgunfold :: forall (c :: * -> *).
(forall b r. Data b => c (b -> r) -> c r)
-> (forall r. r -> c r) -> Constr -> c Encoding
gfoldl :: (forall d b. Data d => c (d -> b) -> d -> c b)
-> (forall g. g -> c g) -> Encoding -> c Encoding
$cgfoldl :: forall (c :: * -> *).
(forall d b. Data d => c (d -> b) -> d -> c b)
-> (forall g. g -> c g) -> Encoding -> c Encoding
$cp1Data :: Typeable Encoding
Data, Encoding -> Encoding -> Bool
(Encoding -> Encoding -> Bool)
-> (Encoding -> Encoding -> Bool) -> Eq Encoding
forall a. (a -> a -> Bool) -> (a -> a -> Bool) -> Eq a
/= :: Encoding -> Encoding -> Bool
$c/= :: Encoding -> Encoding -> Bool
== :: Encoding -> Encoding -> Bool
$c== :: Encoding -> Encoding -> Bool
Eq, Eq Encoding
Eq Encoding
-> (Encoding -> Encoding -> Ordering)
-> (Encoding -> Encoding -> Bool)
-> (Encoding -> Encoding -> Bool)
-> (Encoding -> Encoding -> Bool)
-> (Encoding -> Encoding -> Bool)
-> (Encoding -> Encoding -> Encoding)
-> (Encoding -> Encoding -> Encoding)
-> Ord Encoding
Encoding -> Encoding -> Bool
Encoding -> Encoding -> Ordering
Encoding -> Encoding -> Encoding
forall a.
Eq a
-> (a -> a -> Ordering)
-> (a -> a -> Bool)
-> (a -> a -> Bool)
-> (a -> a -> Bool)
-> (a -> a -> Bool)
-> (a -> a -> a)
-> (a -> a -> a)
-> Ord a
min :: Encoding -> Encoding -> Encoding
$cmin :: Encoding -> Encoding -> Encoding
max :: Encoding -> Encoding -> Encoding
$cmax :: Encoding -> Encoding -> Encoding
>= :: Encoding -> Encoding -> Bool
$c>= :: Encoding -> Encoding -> Bool
> :: Encoding -> Encoding -> Bool
$c> :: Encoding -> Encoding -> Bool
<= :: Encoding -> Encoding -> Bool
$c<= :: Encoding -> Encoding -> Bool
< :: Encoding -> Encoding -> Bool
$c< :: Encoding -> Encoding -> Bool
compare :: Encoding -> Encoding -> Ordering
$ccompare :: Encoding -> Encoding -> Ordering
$cp1Ord :: Eq Encoding
Ord, Int -> Encoding -> [Char] -> [Char]
[Encoding] -> [Char] -> [Char]
Encoding -> [Char]
(Int -> Encoding -> [Char] -> [Char])
-> (Encoding -> [Char])
-> ([Encoding] -> [Char] -> [Char])
-> Show Encoding
forall a.
(Int -> a -> [Char] -> [Char])
-> (a -> [Char]) -> ([a] -> [Char] -> [Char]) -> Show a
showList :: [Encoding] -> [Char] -> [Char]
$cshowList :: [Encoding] -> [Char] -> [Char]
show :: Encoding -> [Char]
$cshow :: Encoding -> [Char]
showsPrec :: Int -> Encoding -> [Char] -> [Char]
$cshowsPrec :: Int -> Encoding -> [Char] -> [Char]
Show, Int -> Encoding
Encoding -> Int
Encoding -> [Encoding]
Encoding -> Encoding
Encoding -> Encoding -> [Encoding]
Encoding -> Encoding -> Encoding -> [Encoding]
(Encoding -> Encoding)
-> (Encoding -> Encoding)
-> (Int -> Encoding)
-> (Encoding -> Int)
-> (Encoding -> [Encoding])
-> (Encoding -> Encoding -> [Encoding])
-> (Encoding -> Encoding -> [Encoding])
-> (Encoding -> Encoding -> Encoding -> [Encoding])
-> Enum Encoding
forall a.
(a -> a)
-> (a -> a)
-> (Int -> a)
-> (a -> Int)
-> (a -> [a])
-> (a -> a -> [a])
-> (a -> a -> [a])
-> (a -> a -> a -> [a])
-> Enum a
enumFromThenTo :: Encoding -> Encoding -> Encoding -> [Encoding]
$cenumFromThenTo :: Encoding -> Encoding -> Encoding -> [Encoding]
enumFromTo :: Encoding -> Encoding -> [Encoding]
$cenumFromTo :: Encoding -> Encoding -> [Encoding]
enumFromThen :: Encoding -> Encoding -> [Encoding]
$cenumFromThen :: Encoding -> Encoding -> [Encoding]
enumFrom :: Encoding -> [Encoding]
$cenumFrom :: Encoding -> [Encoding]
fromEnum :: Encoding -> Int
$cfromEnum :: Encoding -> Int
toEnum :: Int -> Encoding
$ctoEnum :: Int -> Encoding
pred :: Encoding -> Encoding
$cpred :: Encoding -> Encoding
succ :: Encoding -> Encoding
$csucc :: Encoding -> Encoding
Enum, Encoding
Encoding -> Encoding -> Bounded Encoding
forall a. a -> a -> Bounded a
maxBound :: Encoding
$cmaxBound :: Encoding
minBound :: Encoding
$cminBound :: Encoding
Bounded)

fromEncoderBytes :: ( Encoder.Encoding encoding
                    , PrimType (Encoder.Unit encoding)
                    )
                 => encoding
                 -> UArray Word8
                 -> (String, Maybe ValidationFailure, UArray Word8)
fromEncoderBytes :: encoding
-> UArray Word8 -> (String, Maybe ValidationFailure, UArray Word8)
fromEncoderBytes encoding
enc UArray Word8
bytes =
    case (forall s.
 ST
   s (Either (Offset (Unit encoding), Error encoding) (UArray Word8)))
-> Either (Offset (Unit encoding), Error encoding) (UArray Word8)
forall a. (forall s. ST s a) -> a
runST ((forall s.
  ST
    s (Either (Offset (Unit encoding), Error encoding) (UArray Word8)))
 -> Either (Offset (Unit encoding), Error encoding) (UArray Word8))
-> (forall s.
    ST
      s (Either (Offset (Unit encoding), Error encoding) (UArray Word8)))
-> Either (Offset (Unit encoding), Error encoding) (UArray Word8)
forall a b. (a -> b) -> a -> b
$ encoding
-> EncoderUTF8
-> UArray (Unit encoding)
-> ST
     s
     (Either
        (Offset (Unit encoding), Error encoding)
        (UArray (Unit EncoderUTF8)))
forall (st :: * -> *) input output.
(PrimMonad st, Monad st, Encoding input, PrimType (Unit input),
 Encoding output, PrimType (Unit output)) =>
input
-> output
-> UArray (Unit input)
-> st
     (Either (Offset (Unit input), Error input) (UArray (Unit output)))
Encoder.convertFromTo encoding
enc EncoderUTF8
EncoderUTF8 (UArray Word8 -> UArray (Unit encoding)
forall a b. (PrimType a, PrimType b) => UArray a -> UArray b
Vec.recast UArray Word8
bytes) of
        -- TODO: Don't swallow up specific error (second element of pair)
        -- TODO: Confused why all this recasting is necessary. I "typed hole"-ed my way to get this function to compile.  Feels like there should be a cleaner method.
        Left (Offset (Unit encoding)
off, Error encoding
_) ->
            let (UArray (Unit encoding)
b1, UArray (Unit encoding)
b2) = CountOf (Unit encoding)
-> UArray (Unit encoding)
-> (UArray (Unit encoding), UArray (Unit encoding))
forall ty. CountOf ty -> UArray ty -> (UArray ty, UArray ty)
Vec.splitAt (Offset (Unit encoding) -> CountOf (Unit encoding)
forall a. Offset a -> CountOf a
offsetAsSize Offset (Unit encoding)
off) (UArray Word8 -> UArray (Unit encoding)
forall a b. (PrimType a, PrimType b) => UArray a -> UArray b
Vec.recast UArray Word8
bytes)
            in (UArray Word8 -> String
String (UArray Word8 -> String) -> UArray Word8 -> String
forall a b. (a -> b) -> a -> b
$ UArray (Unit encoding) -> UArray Word8
forall a b. (PrimType a, PrimType b) => UArray a -> UArray b
Vec.recast UArray (Unit encoding)
b1, ValidationFailure -> Maybe ValidationFailure
forall a. a -> Maybe a
Just ValidationFailure
BuildingFailure, UArray (Unit encoding) -> UArray Word8
forall a b. (PrimType a, PrimType b) => UArray a -> UArray b
Vec.recast UArray (Unit encoding)
b2)
        Right UArray Word8
converted -> (UArray Word8 -> String
String UArray Word8
converted, Maybe ValidationFailure
forall a. Maybe a
Nothing, UArray Word8
forall a. Monoid a => a
mempty)

-- | Convert a ByteArray to a string assuming a specific encoding.
--
-- It returns a 3-tuple of:
--
-- * The string that has been succesfully converted without any error
-- * An optional validation error
-- * The remaining buffer that hasn't been processed (either as a result of an error, or because the encoded sequence is not fully available)
--
-- Considering a stream of data that is fetched chunk by chunk, it's valid to assume
-- that some sequence might fall in a chunk boundary. When converting chunks,
-- if the error is Nothing and the remaining buffer is not empty, then this buffer
-- need to be prepended to the next chunk
fromBytes :: Encoding -> UArray Word8 -> (String, Maybe ValidationFailure, UArray Word8)
fromBytes :: Encoding
-> UArray Word8 -> (String, Maybe ValidationFailure, UArray Word8)
fromBytes Encoding
ASCII7     UArray Word8
bytes = ASCII7
-> UArray Word8 -> (String, Maybe ValidationFailure, UArray Word8)
forall encoding.
(Encoding encoding, PrimType (Unit encoding)) =>
encoding
-> UArray Word8 -> (String, Maybe ValidationFailure, UArray Word8)
fromEncoderBytes ASCII7
Encoder.ASCII7     UArray Word8
bytes
fromBytes Encoding
ISO_8859_1 UArray Word8
bytes = ISO_8859_1
-> UArray Word8 -> (String, Maybe ValidationFailure, UArray Word8)
forall encoding.
(Encoding encoding, PrimType (Unit encoding)) =>
encoding
-> UArray Word8 -> (String, Maybe ValidationFailure, UArray Word8)
fromEncoderBytes ISO_8859_1
Encoder.ISO_8859_1 UArray Word8
bytes
fromBytes Encoding
UTF16      UArray Word8
bytes = UTF16
-> UArray Word8 -> (String, Maybe ValidationFailure, UArray Word8)
forall encoding.
(Encoding encoding, PrimType (Unit encoding)) =>
encoding
-> UArray Word8 -> (String, Maybe ValidationFailure, UArray Word8)
fromEncoderBytes UTF16
Encoder.UTF16      UArray Word8
bytes
fromBytes Encoding
UTF32      UArray Word8
bytes = UTF32
-> UArray Word8 -> (String, Maybe ValidationFailure, UArray Word8)
forall encoding.
(Encoding encoding, PrimType (Unit encoding)) =>
encoding
-> UArray Word8 -> (String, Maybe ValidationFailure, UArray Word8)
fromEncoderBytes UTF32
Encoder.UTF32      UArray Word8
bytes
fromBytes Encoding
UTF8       UArray Word8
bytes
    | UArray Word8 -> Bool
forall ty. UArray ty -> Bool
C.null UArray Word8
bytes = (String
forall a. Monoid a => a
mempty, Maybe ValidationFailure
forall a. Maybe a
Nothing, UArray Word8
forall a. Monoid a => a
mempty)
    | Bool
otherwise    =
        case UArray Word8
-> Offset Word8
-> CountOf Word8
-> (Offset Word8, Maybe ValidationFailure)
validate UArray Word8
bytes (Int -> Offset Word8
forall ty. Int -> Offset ty
Offset Int
0) (UArray Word8 -> CountOf Word8
forall ty. UArray ty -> CountOf ty
C.length UArray Word8
bytes) of
            (Offset Word8
_, Maybe ValidationFailure
Nothing)  -> (UArray Word8 -> String
fromBytesUnsafe UArray Word8
bytes, Maybe ValidationFailure
forall a. Maybe a
Nothing, UArray Word8
forall a. Monoid a => a
mempty)
            (Offset Word8
pos, Just ValidationFailure
vf) ->
                let (UArray Word8
b1, UArray Word8
b2) = CountOf Word8 -> UArray Word8 -> (UArray Word8, UArray Word8)
forall ty. CountOf ty -> UArray ty -> (UArray ty, UArray ty)
C.splitAt (Offset Word8 -> CountOf Word8
forall a. Offset a -> CountOf a
offsetAsSize Offset Word8
pos) UArray Word8
bytes
                 in (UArray Word8 -> String
fromBytesUnsafe UArray Word8
b1, ValidationFailure -> Maybe ValidationFailure
toErr ValidationFailure
vf, UArray Word8
b2)
  where
    toErr :: ValidationFailure -> Maybe ValidationFailure
toErr ValidationFailure
MissingByte         = Maybe ValidationFailure
forall a. Maybe a
Nothing
    toErr ValidationFailure
InvalidHeader       = ValidationFailure -> Maybe ValidationFailure
forall a. a -> Maybe a
Just ValidationFailure
InvalidHeader
    toErr ValidationFailure
InvalidContinuation = ValidationFailure -> Maybe ValidationFailure
forall a. a -> Maybe a
Just ValidationFailure
InvalidContinuation
    toErr ValidationFailure
BuildingFailure     = ValidationFailure -> Maybe ValidationFailure
forall a. a -> Maybe a
Just ValidationFailure
BuildingFailure

-- | Convert a UTF8 array of bytes to a String.
--
-- If there's any error in the stream, it will automatically
-- insert replacement bytes to replace invalid sequences.
--
-- In the case of sequence that fall in the middle of 2 chunks,
-- the remaining buffer is supposed to be preprended to the
-- next chunk, and resume the parsing.
fromBytesLenient :: UArray Word8 -> (String, UArray Word8)
fromBytesLenient :: UArray Word8 -> (String, UArray Word8)
fromBytesLenient UArray Word8
bytes
    | UArray Word8 -> Bool
forall ty. UArray ty -> Bool
C.null UArray Word8
bytes = (String
forall a. Monoid a => a
mempty, UArray Word8
forall a. Monoid a => a
mempty)
    | Bool
otherwise    =
        case UArray Word8
-> Offset Word8
-> CountOf Word8
-> (Offset Word8, Maybe ValidationFailure)
validate UArray Word8
bytes (Int -> Offset Word8
forall ty. Int -> Offset ty
Offset Int
0) (UArray Word8 -> CountOf Word8
forall ty. UArray ty -> CountOf ty
C.length UArray Word8
bytes) of
            (Offset Word8
_, Maybe ValidationFailure
Nothing)                   -> (UArray Word8 -> String
fromBytesUnsafe UArray Word8
bytes, UArray Word8
forall a. Monoid a => a
mempty)
            -- TODO: Should anything be done in the 'BuildingFailure' case?
            (Offset Word8
_, Just ValidationFailure
BuildingFailure) -> [Char] -> (String, UArray Word8)
forall a. HasCallStack => [Char] -> a
error [Char]
"fromBytesLenient: FIXME!"
            (Offset Word8
pos, Just ValidationFailure
MissingByte) ->
                let (UArray Word8
b1,UArray Word8
b2) = CountOf Word8 -> UArray Word8 -> (UArray Word8, UArray Word8)
forall ty. CountOf ty -> UArray ty -> (UArray ty, UArray ty)
C.splitAt (Offset Word8 -> CountOf Word8
forall a. Offset a -> CountOf a
offsetAsSize Offset Word8
pos) UArray Word8
bytes
                 in (UArray Word8 -> String
fromBytesUnsafe UArray Word8
b1, UArray Word8
b2)
            (Offset Word8
pos, Just ValidationFailure
InvalidHeader) ->
                let (UArray Word8
b1,UArray Word8
b2) = CountOf Word8 -> UArray Word8 -> (UArray Word8, UArray Word8)
forall ty. CountOf ty -> UArray ty -> (UArray ty, UArray ty)
C.splitAt (Offset Word8 -> CountOf Word8
forall a. Offset a -> CountOf a
offsetAsSize Offset Word8
pos) UArray Word8
bytes
                    (UArray Word8
_,UArray Word8
b3)  = CountOf Word8 -> UArray Word8 -> (UArray Word8, UArray Word8)
forall ty. CountOf ty -> UArray ty -> (UArray ty, UArray ty)
C.splitAt CountOf Word8
1 UArray Word8
b2
                    (String
s3, UArray Word8
r) = UArray Word8 -> (String, UArray Word8)
fromBytesLenient UArray Word8
b3
                 in ([String] -> String
forall a. Monoid a => [a] -> a
mconcat [UArray Word8 -> String
fromBytesUnsafe UArray Word8
b1,String
replacement, String
s3], UArray Word8
r)
            (Offset Word8
pos, Just ValidationFailure
InvalidContinuation) ->
                let (UArray Word8
b1,UArray Word8
b2) = CountOf Word8 -> UArray Word8 -> (UArray Word8, UArray Word8)
forall ty. CountOf ty -> UArray ty -> (UArray ty, UArray ty)
C.splitAt (Offset Word8 -> CountOf Word8
forall a. Offset a -> CountOf a
offsetAsSize Offset Word8
pos) UArray Word8
bytes
                    (UArray Word8
_,UArray Word8
b3)  = CountOf Word8 -> UArray Word8 -> (UArray Word8, UArray Word8)
forall ty. CountOf ty -> UArray ty -> (UArray ty, UArray ty)
C.splitAt CountOf Word8
1 UArray Word8
b2
                    (String
s3, UArray Word8
r) = UArray Word8 -> (String, UArray Word8)
fromBytesLenient UArray Word8
b3
                 in ([String] -> String
forall a. Monoid a => [a] -> a
mconcat [UArray Word8 -> String
fromBytesUnsafe UArray Word8
b1,String
replacement, String
s3], UArray Word8
r)
  where
    -- This is the replacement character U+FFFD used for any invalid header or continuation
    replacement :: String
    !replacement :: String
replacement = UArray Word8 -> String
fromBytesUnsafe (UArray Word8 -> String) -> UArray Word8 -> String
forall a b. (a -> b) -> a -> b
$ [Item (UArray Word8)] -> UArray Word8
forall l. IsList l => [Item l] -> l
fromList [Item (UArray Word8)
0xef,Item (UArray Word8)
0xbf,Item (UArray Word8)
0xbd]

-- | Decode a stream of binary chunks containing UTF8 encoding in a list of valid String
--
-- Chunk not necessarily contains a valid string, as
-- a UTF8 sequence could be split over 2 chunks.
fromChunkBytes :: [UArray Word8] -> [String]
fromChunkBytes :: [UArray Word8] -> [String]
fromChunkBytes [UArray Word8]
l = [UArray Word8] -> [String]
loop [UArray Word8]
l
  where
    loop :: [UArray Word8] -> [String]
loop []         = []
    loop [UArray Word8
bytes]    =
        case UArray Word8
-> Offset Word8
-> CountOf Word8
-> (Offset Word8, Maybe ValidationFailure)
validate UArray Word8
bytes (Int -> Offset Word8
forall ty. Int -> Offset ty
Offset Int
0) (UArray Word8 -> CountOf Word8
forall ty. UArray ty -> CountOf ty
C.length UArray Word8
bytes) of
            (Offset Word8
_, Maybe ValidationFailure
Nothing)  -> [UArray Word8 -> String
fromBytesUnsafe UArray Word8
bytes]
            (Offset Word8
_, Just ValidationFailure
err) -> ValidationFailure -> [String]
forall a a. Show a => a -> a
doErr ValidationFailure
err
    loop (UArray Word8
bytes:cs :: [UArray Word8]
cs@(UArray Word8
c1:[UArray Word8]
c2)) =
        case UArray Word8
-> Offset Word8
-> CountOf Word8
-> (Offset Word8, Maybe ValidationFailure)
validate UArray Word8
bytes (Int -> Offset Word8
forall ty. Int -> Offset ty
Offset Int
0) (UArray Word8 -> CountOf Word8
forall ty. UArray ty -> CountOf ty
C.length UArray Word8
bytes) of
            (Offset Word8
_, Maybe ValidationFailure
Nothing) -> UArray Word8 -> String
fromBytesUnsafe UArray Word8
bytes String -> [String] -> [String]
forall a. a -> [a] -> [a]
: [UArray Word8] -> [String]
loop [UArray Word8]
cs
            (Offset Word8
pos, Just ValidationFailure
MissingByte) ->
                let (UArray Word8
b1,UArray Word8
b2) = CountOf Word8 -> UArray Word8 -> (UArray Word8, UArray Word8)
forall ty. CountOf ty -> UArray ty -> (UArray ty, UArray ty)
C.splitAt (Offset Word8 -> CountOf Word8
forall a. Offset a -> CountOf a
offsetAsSize Offset Word8
pos) UArray Word8
bytes
                 in UArray Word8 -> String
fromBytesUnsafe UArray Word8
b1 String -> [String] -> [String]
forall a. a -> [a] -> [a]
: [UArray Word8] -> [String]
loop ((UArray Word8
b2 UArray Word8 -> UArray Word8 -> UArray Word8
forall a. Monoid a => a -> a -> a
`mappend` UArray Word8
c1) UArray Word8 -> [UArray Word8] -> [UArray Word8]
forall a. a -> [a] -> [a]
: [UArray Word8]
c2)
            (Offset Word8
_, Just ValidationFailure
err) -> ValidationFailure -> [String]
forall a a. Show a => a -> a
doErr ValidationFailure
err
    doErr :: a -> a
doErr a
err = [Char] -> a
forall a. HasCallStack => [Char] -> a
error ([Char]
"fromChunkBytes: " [Char] -> [Char] -> [Char]
forall a. Semigroup a => a -> a -> a
<> a -> [Char]
forall a. Show a => a -> [Char]
show a
err)

-- | Convert a Byte Array representing UTF8 data directly to a string without checking for UTF8 validity
--
-- If the input contains invalid sequences, it will trigger runtime async errors when processing data.
--
-- In doubt, use 'fromBytes'
fromBytesUnsafe :: UArray Word8 -> String
fromBytesUnsafe :: UArray Word8 -> String
fromBytesUnsafe = UArray Word8 -> String
String

toEncoderBytes :: ( Encoder.Encoding encoding
                  , PrimType (Encoder.Unit encoding)
                  , Exception (Encoder.Error encoding)
                  )
               => encoding
               -> UArray Word8
               -> UArray Word8
toEncoderBytes :: encoding -> UArray Word8 -> UArray Word8
toEncoderBytes encoding
enc UArray Word8
bytes = UArray (Unit encoding) -> UArray Word8
forall a b. (PrimType a, PrimType b) => UArray a -> UArray b
Vec.recast (UArray (Unit encoding) -> UArray Word8)
-> UArray (Unit encoding) -> UArray Word8
forall a b. (a -> b) -> a -> b
$
  case (forall s.
 ST
   s
   (Either
      (Offset Word8, ValidationFailure) (UArray (Unit encoding))))
-> Either
     (Offset Word8, ValidationFailure) (UArray (Unit encoding))
forall a. (forall s. ST s a) -> a
runST ((forall s.
  ST
    s
    (Either
       (Offset Word8, ValidationFailure) (UArray (Unit encoding))))
 -> Either
      (Offset Word8, ValidationFailure) (UArray (Unit encoding)))
-> (forall s.
    ST
      s
      (Either
         (Offset Word8, ValidationFailure) (UArray (Unit encoding))))
-> Either
     (Offset Word8, ValidationFailure) (UArray (Unit encoding))
forall a b. (a -> b) -> a -> b
$ EncoderUTF8
-> encoding
-> UArray (Unit EncoderUTF8)
-> ST
     s
     (Either
        (Offset (Unit EncoderUTF8), Error EncoderUTF8)
        (UArray (Unit encoding)))
forall (st :: * -> *) input output.
(PrimMonad st, Monad st, Encoding input, PrimType (Unit input),
 Encoding output, PrimType (Unit output)) =>
input
-> output
-> UArray (Unit input)
-> st
     (Either (Offset (Unit input), Error input) (UArray (Unit output)))
Encoder.convertFromTo EncoderUTF8
EncoderUTF8 encoding
enc UArray Word8
UArray (Unit EncoderUTF8)
bytes of
    Left (Offset Word8, ValidationFailure)
_ -> [Char] -> UArray (Unit encoding)
forall a. HasCallStack => [Char] -> a
error [Char]
"toEncoderBytes: FIXME!"
    Right UArray (Unit encoding)
converted -> UArray (Unit encoding)
converted

-- | Convert a String to a bytearray in a specific encoding
--
-- if the encoding is UTF8, the underlying buffer is returned without extra allocation or any processing
--
-- In any other encoding, some allocation and processing are done to convert.
toBytes :: Encoding -> String -> UArray Word8
toBytes :: Encoding -> String -> UArray Word8
toBytes Encoding
UTF8       (String UArray Word8
bytes) = UArray Word8
bytes
toBytes Encoding
ASCII7     (String UArray Word8
bytes) = ASCII7 -> UArray Word8 -> UArray Word8
forall encoding.
(Encoding encoding, PrimType (Unit encoding),
 Exception (Error encoding)) =>
encoding -> UArray Word8 -> UArray Word8
toEncoderBytes ASCII7
Encoder.ASCII7     UArray Word8
bytes
toBytes Encoding
ISO_8859_1 (String UArray Word8
bytes) = ISO_8859_1 -> UArray Word8 -> UArray Word8
forall encoding.
(Encoding encoding, PrimType (Unit encoding),
 Exception (Error encoding)) =>
encoding -> UArray Word8 -> UArray Word8
toEncoderBytes ISO_8859_1
Encoder.ISO_8859_1 UArray Word8
bytes
toBytes Encoding
UTF16      (String UArray Word8
bytes) = UTF16 -> UArray Word8 -> UArray Word8
forall encoding.
(Encoding encoding, PrimType (Unit encoding),
 Exception (Error encoding)) =>
encoding -> UArray Word8 -> UArray Word8
toEncoderBytes UTF16
Encoder.UTF16      UArray Word8
bytes
toBytes Encoding
UTF32      (String UArray Word8
bytes) = UTF32 -> UArray Word8 -> UArray Word8
forall encoding.
(Encoding encoding, PrimType (Unit encoding),
 Exception (Error encoding)) =>
encoding -> UArray Word8 -> UArray Word8
toEncoderBytes UTF32
Encoder.UTF32      UArray Word8
bytes

-- | Split lines in a string using newline as separation.
--
-- Note that carriage return preceding a newline are also strip for
-- maximum compatibility between Windows and Unix system.
lines :: String -> [String]
lines :: String -> [String]
lines String
s =
    case String -> Either Bool (String, String)
breakLine String
s of
        Left Bool
_         -> [String
s]
        Right (String
line,String
r) -> String
line String -> [String] -> [String]
forall a. a -> [a] -> [a]
: String -> [String]
lines String
r

-- | Split words in a string using spaces as separation
--
-- > words "Hello Foundation"
-- [ "Hello", "Foundation" ]
words :: String -> [String]
words :: String -> [String]
words = ([Char] -> String) -> [[Char]] -> [String]
forall (f :: * -> *) a b. Functor f => (a -> b) -> f a -> f b
fmap [Char] -> String
forall l. IsList l => [Item l] -> l
fromList ([[Char]] -> [String])
-> (String -> [[Char]]) -> String -> [String]
forall k (cat :: k -> k -> *) (b :: k) (c :: k) (a :: k).
Category cat =>
cat b c -> cat a b -> cat a c
. [Char] -> [[Char]]
Prelude.words ([Char] -> [[Char]]) -> (String -> [Char]) -> String -> [[Char]]
forall k (cat :: k -> k -> *) (b :: k) (c :: k) (a :: k).
Category cat =>
cat b c -> cat a b -> cat a c
. String -> [Char]
forall l. IsList l => l -> [Item l]
toList

-- | Append a character to a String builder
builderAppend :: PrimMonad state => Char -> Builder String MutableString Word8 state err ()
builderAppend :: Char -> Builder String MutableString Word8 state err ()
builderAppend Char
c = State
  (Offset Word8,
   BuildingState String MutableString Word8 (PrimState state),
   Maybe err)
  state
  ()
-> Builder String MutableString Word8 state err ()
forall collection (mutCollection :: * -> *) step (state :: * -> *)
       err a.
State
  (Offset step,
   BuildingState collection mutCollection step (PrimState state),
   Maybe err)
  state
  a
-> Builder collection mutCollection step state err a
Builder (State
   (Offset Word8,
    BuildingState String MutableString Word8 (PrimState state),
    Maybe err)
   state
   ()
 -> Builder String MutableString Word8 state err ())
-> State
     (Offset Word8,
      BuildingState String MutableString Word8 (PrimState state),
      Maybe err)
     state
     ()
-> Builder String MutableString Word8 state err ()
forall a b. (a -> b) -> a -> b
$ ((Offset Word8,
  BuildingState String MutableString Word8 (PrimState state),
  Maybe err)
 -> state
      ((),
       (Offset Word8,
        BuildingState String MutableString Word8 (PrimState state),
        Maybe err)))
-> State
     (Offset Word8,
      BuildingState String MutableString Word8 (PrimState state),
      Maybe err)
     state
     ()
forall s (m :: * -> *) a. (s -> m (a, s)) -> State s m a
State (((Offset Word8,
   BuildingState String MutableString Word8 (PrimState state),
   Maybe err)
  -> state
       ((),
        (Offset Word8,
         BuildingState String MutableString Word8 (PrimState state),
         Maybe err)))
 -> State
      (Offset Word8,
       BuildingState String MutableString Word8 (PrimState state),
       Maybe err)
      state
      ())
-> ((Offset Word8,
     BuildingState String MutableString Word8 (PrimState state),
     Maybe err)
    -> state
         ((),
          (Offset Word8,
           BuildingState String MutableString Word8 (PrimState state),
           Maybe err)))
-> State
     (Offset Word8,
      BuildingState String MutableString Word8 (PrimState state),
      Maybe err)
     state
     ()
forall a b. (a -> b) -> a -> b
$ \(Offset Word8
i, BuildingState String MutableString Word8 (PrimState state)
st, Maybe err
e) ->
    if Offset Word8 -> CountOf Word8
forall a. Offset a -> CountOf a
offsetAsSize Offset Word8
i CountOf Word8 -> CountOf Word8 -> CountOf Word8
forall a. Additive a => a -> a -> a
+ CountOf Word8
nbBytes CountOf Word8 -> CountOf Word8 -> Bool
forall a. Ord a => a -> a -> Bool
>= BuildingState String MutableString Word8 (PrimState state)
-> CountOf Word8
forall collection (mutCollection :: * -> *) step state.
BuildingState collection mutCollection step state -> CountOf step
chunkSize BuildingState String MutableString Word8 (PrimState state)
st
        then do
            String
cur      <- MutableString (PrimState state) -> CountOf Word8 -> state String
forall (prim :: * -> *).
PrimMonad prim =>
MutableString (PrimState prim) -> CountOf Word8 -> prim String
unsafeFreezeShrink (BuildingState String MutableString Word8 (PrimState state)
-> MutableString (PrimState state)
forall collection (mutCollection :: * -> *) step state.
BuildingState collection mutCollection step state
-> mutCollection state
curChunk BuildingState String MutableString Word8 (PrimState state)
st) (Offset Word8 -> CountOf Word8
forall a. Offset a -> CountOf a
offsetAsSize Offset Word8
i)
            MutableString (PrimState state)
newChunk <- CountOf Word8 -> state (MutableString (PrimState state))
forall (prim :: * -> *).
PrimMonad prim =>
CountOf Word8 -> prim (MutableString (PrimState prim))
new (BuildingState String MutableString Word8 (PrimState state)
-> CountOf Word8
forall collection (mutCollection :: * -> *) step state.
BuildingState collection mutCollection step state -> CountOf step
chunkSize BuildingState String MutableString Word8 (PrimState state)
st)
            MutableString (PrimState state)
-> Offset Word8 -> UTF8Char -> state ()
forall (prim :: * -> *).
PrimMonad prim =>
MutableString (PrimState prim)
-> Offset Word8 -> UTF8Char -> prim ()
writeUTF8Char MutableString (PrimState state)
newChunk (Int -> Offset Word8
forall ty. Int -> Offset ty
Offset Int
0) UTF8Char
utf8Char
            ((),
 (Offset Word8,
  BuildingState String MutableString Word8 (PrimState state),
  Maybe err))
-> state
     ((),
      (Offset Word8,
       BuildingState String MutableString Word8 (PrimState state),
       Maybe err))
forall (m :: * -> *) a. Monad m => a -> m a
return ((), (CountOf Word8 -> Offset Word8
forall a. CountOf a -> Offset a
sizeAsOffset CountOf Word8
nbBytes, BuildingState String MutableString Word8 (PrimState state)
st { prevChunks :: [String]
prevChunks     = String
cur String -> [String] -> [String]
forall a. a -> [a] -> [a]
: BuildingState String MutableString Word8 (PrimState state)
-> [String]
forall collection (mutCollection :: * -> *) step state.
BuildingState collection mutCollection step state -> [collection]
prevChunks BuildingState String MutableString Word8 (PrimState state)
st
                                                  , prevChunksSize :: CountOf Word8
prevChunksSize = Offset Word8 -> CountOf Word8
forall a. Offset a -> CountOf a
offsetAsSize Offset Word8
i CountOf Word8 -> CountOf Word8 -> CountOf Word8
forall a. Additive a => a -> a -> a
+ BuildingState String MutableString Word8 (PrimState state)
-> CountOf Word8
forall collection (mutCollection :: * -> *) step state.
BuildingState collection mutCollection step state -> CountOf step
prevChunksSize BuildingState String MutableString Word8 (PrimState state)
st
                                                  , curChunk :: MutableString (PrimState state)
curChunk       = MutableString (PrimState state)
newChunk
                                                  }, Maybe err
e))
        else do
            MutableString (PrimState state)
-> Offset Word8 -> UTF8Char -> state ()
forall (prim :: * -> *).
PrimMonad prim =>
MutableString (PrimState prim)
-> Offset Word8 -> UTF8Char -> prim ()
writeUTF8Char (BuildingState String MutableString Word8 (PrimState state)
-> MutableString (PrimState state)
forall collection (mutCollection :: * -> *) step state.
BuildingState collection mutCollection step state
-> mutCollection state
curChunk BuildingState String MutableString Word8 (PrimState state)
st) Offset Word8
i UTF8Char
utf8Char
            ((),
 (Offset Word8,
  BuildingState String MutableString Word8 (PrimState state),
  Maybe err))
-> state
     ((),
      (Offset Word8,
       BuildingState String MutableString Word8 (PrimState state),
       Maybe err))
forall (m :: * -> *) a. Monad m => a -> m a
return ((), (Offset Word8
i Offset Word8 -> Offset Word8 -> Offset Word8
forall a. Additive a => a -> a -> a
+ CountOf Word8 -> Offset Word8
forall a. CountOf a -> Offset a
sizeAsOffset CountOf Word8
nbBytes, BuildingState String MutableString Word8 (PrimState state)
st, Maybe err
e))
  where
    utf8Char :: UTF8Char
utf8Char = Char -> UTF8Char
asUTF8Char Char
c
    nbBytes :: CountOf Word8
nbBytes  = UTF8Char -> CountOf Word8
numBytes UTF8Char
utf8Char

-- | Create a new String builder using chunks of @sizeChunksI@
builderBuild :: PrimMonad m => Int -> Builder String MutableString Word8 m err () -> m (Either err String)
builderBuild :: Int
-> Builder String MutableString Word8 m err ()
-> m (Either err String)
builderBuild Int
sizeChunksI Builder String MutableString Word8 m err ()
sb
    | Int
sizeChunksI Int -> Int -> Bool
forall a. Ord a => a -> a -> Bool
<= Int
3 = Int
-> Builder String MutableString Word8 m err ()
-> m (Either err String)
forall (m :: * -> *) err.
PrimMonad m =>
Int
-> Builder String MutableString Word8 m err ()
-> m (Either err String)
builderBuild Int
64 Builder String MutableString Word8 m err ()
sb
    | Bool
otherwise        = do
        MutableString (PrimState m)
firstChunk <- CountOf Word8 -> m (MutableString (PrimState m))
forall (prim :: * -> *).
PrimMonad prim =>
CountOf Word8 -> prim (MutableString (PrimState prim))
new CountOf Word8
sizeChunks
        (Offset Word8
i, BuildingState String MutableString Word8 (PrimState m)
st, Maybe err
e) <- ((),
 (Offset Word8,
  BuildingState String MutableString Word8 (PrimState m), Maybe err))
-> (Offset Word8,
    BuildingState String MutableString Word8 (PrimState m), Maybe err)
forall a b. (a, b) -> b
snd (((),
  (Offset Word8,
   BuildingState String MutableString Word8 (PrimState m), Maybe err))
 -> (Offset Word8,
     BuildingState String MutableString Word8 (PrimState m), Maybe err))
-> m ((),
      (Offset Word8,
       BuildingState String MutableString Word8 (PrimState m), Maybe err))
-> m (Offset Word8,
      BuildingState String MutableString Word8 (PrimState m), Maybe err)
forall (f :: * -> *) a b. Functor f => (a -> b) -> f a -> f b
<$> State
  (Offset Word8,
   BuildingState String MutableString Word8 (PrimState m), Maybe err)
  m
  ()
-> (Offset Word8,
    BuildingState String MutableString Word8 (PrimState m), Maybe err)
-> m ((),
      (Offset Word8,
       BuildingState String MutableString Word8 (PrimState m), Maybe err))
forall s (m :: * -> *) a. State s m a -> s -> m (a, s)
runState (Builder String MutableString Word8 m err ()
-> State
     (Offset Word8,
      BuildingState String MutableString Word8 (PrimState m), Maybe err)
     m
     ()
forall collection (mutCollection :: * -> *) step (state :: * -> *)
       err a.
Builder collection mutCollection step state err a
-> State
     (Offset step,
      BuildingState collection mutCollection step (PrimState state),
      Maybe err)
     state
     a
runBuilder Builder String MutableString Word8 m err ()
sb) (Int -> Offset Word8
forall ty. Int -> Offset ty
Offset Int
0, [String]
-> CountOf Word8
-> MutableString (PrimState m)
-> CountOf Word8
-> BuildingState String MutableString Word8 (PrimState m)
forall collection (mutCollection :: * -> *) step state.
[collection]
-> CountOf step
-> mutCollection state
-> CountOf step
-> BuildingState collection mutCollection step state
BuildingState [] (Int -> CountOf Word8
forall ty. Int -> CountOf ty
CountOf Int
0) MutableString (PrimState m)
firstChunk CountOf Word8
sizeChunks, Maybe err
forall a. Maybe a
Nothing)
        case Maybe err
e of
          Just err
err -> Either err String -> m (Either err String)
forall (m :: * -> *) a. Monad m => a -> m a
return (err -> Either err String
forall a b. a -> Either a b
Left err
err)
          Maybe err
Nothing -> do
            String
cur <- MutableString (PrimState m) -> CountOf Word8 -> m String
forall (prim :: * -> *).
PrimMonad prim =>
MutableString (PrimState prim) -> CountOf Word8 -> prim String
unsafeFreezeShrink (BuildingState String MutableString Word8 (PrimState m)
-> MutableString (PrimState m)
forall collection (mutCollection :: * -> *) step state.
BuildingState collection mutCollection step state
-> mutCollection state
curChunk BuildingState String MutableString Word8 (PrimState m)
st) (Offset Word8 -> CountOf Word8
forall a. Offset a -> CountOf a
offsetAsSize Offset Word8
i)
            -- Build final array
            let totalSize :: CountOf Word8
totalSize = BuildingState String MutableString Word8 (PrimState m)
-> CountOf Word8
forall collection (mutCollection :: * -> *) step state.
BuildingState collection mutCollection step state -> CountOf step
prevChunksSize BuildingState String MutableString Word8 (PrimState m)
st CountOf Word8 -> CountOf Word8 -> CountOf Word8
forall a. Additive a => a -> a -> a
+ Offset Word8 -> CountOf Word8
forall a. Offset a -> CountOf a
offsetAsSize Offset Word8
i
            UArray Word8
final <- CountOf Word8 -> m (MUArray Word8 (PrimState m))
forall (prim :: * -> *) ty.
(PrimMonad prim, PrimType ty) =>
CountOf ty -> prim (MUArray ty (PrimState prim))
Vec.new CountOf Word8
totalSize m (MUArray Word8 (PrimState m))
-> (MUArray Word8 (PrimState m) -> m (MUArray Word8 (PrimState m)))
-> m (MUArray Word8 (PrimState m))
forall (m :: * -> *) a b. Monad m => m a -> (a -> m b) -> m b
>>= CountOf Word8
-> [String]
-> MUArray Word8 (PrimState m)
-> m (MUArray Word8 (PrimState m))
forall (m :: * -> *).
PrimMonad m =>
CountOf Word8
-> [String]
-> MUArray Word8 (PrimState m)
-> m (MUArray Word8 (PrimState m))
fillFromEnd CountOf Word8
totalSize (String
cur String -> [String] -> [String]
forall a. a -> [a] -> [a]
: BuildingState String MutableString Word8 (PrimState m) -> [String]
forall collection (mutCollection :: * -> *) step state.
BuildingState collection mutCollection step state -> [collection]
prevChunks BuildingState String MutableString Word8 (PrimState m)
st) m (MUArray Word8 (PrimState m))
-> (MUArray Word8 (PrimState m) -> m (UArray Word8))
-> m (UArray Word8)
forall (m :: * -> *) a b. Monad m => m a -> (a -> m b) -> m b
>>= MUArray Word8 (PrimState m) -> m (UArray Word8)
forall (prim :: * -> *) ty.
PrimMonad prim =>
MUArray ty (PrimState prim) -> prim (UArray ty)
Vec.unsafeFreeze
            Either err String -> m (Either err String)
forall (m :: * -> *) a. Monad m => a -> m a
return (Either err String -> m (Either err String))
-> (UArray Word8 -> Either err String)
-> UArray Word8
-> m (Either err String)
forall k (cat :: k -> k -> *) (b :: k) (c :: k) (a :: k).
Category cat =>
cat b c -> cat a b -> cat a c
. String -> Either err String
forall a b. b -> Either a b
Right (String -> Either err String)
-> (UArray Word8 -> String) -> UArray Word8 -> Either err String
forall k (cat :: k -> k -> *) (b :: k) (c :: k) (a :: k).
Category cat =>
cat b c -> cat a b -> cat a c
. UArray Word8 -> String
String (UArray Word8 -> m (Either err String))
-> UArray Word8 -> m (Either err String)
forall a b. (a -> b) -> a -> b
$ UArray Word8
final
  where
    sizeChunks :: CountOf Word8
sizeChunks = Int -> CountOf Word8
forall ty. Int -> CountOf ty
CountOf Int
sizeChunksI

    fillFromEnd :: CountOf Word8
-> [String]
-> MUArray Word8 (PrimState m)
-> m (MUArray Word8 (PrimState m))
fillFromEnd CountOf Word8
_    []            MUArray Word8 (PrimState m)
mba = MUArray Word8 (PrimState m) -> m (MUArray Word8 (PrimState m))
forall (m :: * -> *) a. Monad m => a -> m a
return MUArray Word8 (PrimState m)
mba
    fillFromEnd !CountOf Word8
end (String UArray Word8
x:[String]
xs) MUArray Word8 (PrimState m)
mba = do
        let sz :: CountOf Word8
sz = UArray Word8 -> CountOf Word8
forall ty. UArray ty -> CountOf ty
Vec.length UArray Word8
x
        let start :: CountOf Word8
start = CountOf Word8
end CountOf Word8 -> CountOf Word8 -> CountOf Word8
forall a. CountOf a -> CountOf a -> CountOf a
`sizeSub` CountOf Word8
sz
        MUArray Word8 (PrimState m)
-> Offset Word8
-> UArray Word8
-> Offset Word8
-> CountOf Word8
-> m ()
forall (prim :: * -> *) ty.
(PrimMonad prim, PrimType ty) =>
MUArray ty (PrimState prim)
-> Offset ty -> UArray ty -> Offset ty -> CountOf ty -> prim ()
Vec.unsafeCopyAtRO MUArray Word8 (PrimState m)
mba (CountOf Word8 -> Offset Word8
forall a. CountOf a -> Offset a
sizeAsOffset CountOf Word8
start) UArray Word8
x (Int -> Offset Word8
forall ty. Int -> Offset ty
Offset Int
0) CountOf Word8
sz
        CountOf Word8
-> [String]
-> MUArray Word8 (PrimState m)
-> m (MUArray Word8 (PrimState m))
fillFromEnd CountOf Word8
start [String]
xs MUArray Word8 (PrimState m)
mba

builderBuild_ :: PrimMonad m => Int -> Builder String MutableString Word8 m () () -> m String
builderBuild_ :: Int -> Builder String MutableString Word8 m () () -> m String
builderBuild_ Int
sizeChunksI Builder String MutableString Word8 m () ()
sb = (() -> String) -> (String -> String) -> Either () String -> String
forall a c b. (a -> c) -> (b -> c) -> Either a b -> c
either (\() -> [Char] -> String
forall a. [Char] -> a
internalError [Char]
"impossible output") String -> String
forall k (cat :: k -> k -> *) (a :: k). Category cat => cat a a
id (Either () String -> String) -> m (Either () String) -> m String
forall (f :: * -> *) a b. Functor f => (a -> b) -> f a -> f b
<$> Int
-> Builder String MutableString Word8 m () ()
-> m (Either () String)
forall (m :: * -> *) err.
PrimMonad m =>
Int
-> Builder String MutableString Word8 m err ()
-> m (Either err String)
builderBuild Int
sizeChunksI Builder String MutableString Word8 m () ()
sb

stringDewrap :: (Block Word8 -> Offset Word8 -> a)
             -> (Ptr Word8 -> Offset Word8 -> ST s a)
             -> String
             -> a
stringDewrap :: (Block Word8 -> Offset Word8 -> a)
-> (Ptr Word8 -> Offset Word8 -> ST s a) -> String -> a
stringDewrap Block Word8 -> Offset Word8 -> a
withBa Ptr Word8 -> Offset Word8 -> ST s a
withPtr (String UArray Word8
ba) = (Block Word8 -> Offset Word8 -> a)
-> (Ptr Word8 -> Offset Word8 -> ST s a) -> UArray Word8 -> a
forall ty a s.
(Block ty -> Offset ty -> a)
-> (Ptr ty -> Offset ty -> ST s a) -> UArray ty -> a
C.unsafeDewrap Block Word8 -> Offset Word8 -> a
withBa Ptr Word8 -> Offset Word8 -> ST s a
withPtr UArray Word8
ba
{-# INLINE stringDewrap #-}

-- | Read an Integer from a String
--
-- Consume an optional minus sign and many digits until end of string.
readIntegral :: (HasNegation i, IntegralUpsize Word8 i, Additive i, Multiplicative i, IsIntegral i) => String -> Maybe i
readIntegral :: String -> Maybe i
readIntegral String
str
    | CountOf Word8
sz CountOf Word8 -> CountOf Word8 -> Bool
forall a. Eq a => a -> a -> Bool
== CountOf Word8
0   = Maybe i
forall a. Maybe a
Nothing
    | Bool
otherwise = (Block Word8 -> Offset Word8 -> Maybe i)
-> (Ptr Word8 -> Offset Word8 -> ST Any (Maybe i))
-> String
-> Maybe i
forall a s.
(Block Word8 -> Offset Word8 -> a)
-> (Ptr Word8 -> Offset Word8 -> ST s a) -> String -> a
stringDewrap Block Word8 -> Offset Word8 -> Maybe i
withBa (\ptr :: Ptr Word8
ptr@(Ptr !Addr#
_) -> Maybe i -> ST Any (Maybe i)
forall (f :: * -> *) a. Applicative f => a -> f a
pure (Maybe i -> ST Any (Maybe i))
-> (Offset Word8 -> Maybe i) -> Offset Word8 -> ST Any (Maybe i)
forall k (cat :: k -> k -> *) (b :: k) (c :: k) (a :: k).
Category cat =>
cat b c -> cat a b -> cat a c
. Ptr Word8 -> Offset Word8 -> Maybe i
withPtr Ptr Word8
ptr) String
str
  where
    !sz :: CountOf Word8
sz = String -> CountOf Word8
size String
str
    withBa :: Block Word8 -> Offset Word8 -> Maybe i
withBa Block Word8
ba Offset Word8
ofs =
        let negativeSign :: Bool
negativeSign = Block Word8 -> Offset Word8 -> Word8 -> Bool
forall container.
Indexable container Word8 =>
container -> Offset Word8 -> Word8 -> Bool
UTF8.expectAscii Block Word8
ba Offset Word8
ofs Word8
0x2d
            startOfs :: Offset Word8
startOfs     = if Bool
negativeSign then Offset Word8 -> Offset Word8
forall a. Enum a => a -> a
succ Offset Word8
ofs else Offset Word8
ofs
         in case i
-> Block Word8
-> Offset Word8
-> Offset Word8
-> (# i, Bool, Offset Word8 #)
forall acc.
(IntegralUpsize Word8 acc, Additive acc, Multiplicative acc,
 Integral acc) =>
acc
-> Block Word8
-> Offset Word8
-> Offset Word8
-> (# acc, Bool, Offset Word8 #)
decimalDigitsBA i
0 Block Word8
ba Offset Word8
endOfs Offset Word8
startOfs of
                (# i
acc, Bool
True, Offset Word8
endOfs' #) | Offset Word8
endOfs' Offset Word8 -> Offset Word8 -> Bool
forall a. Ord a => a -> a -> Bool
> Offset Word8
startOfs -> i -> Maybe i
forall a. a -> Maybe a
Just (i -> Maybe i) -> i -> Maybe i
forall a b. (a -> b) -> a -> b
$! if Bool
negativeSign then i -> i
forall a. HasNegation a => a -> a
negate i
acc else i
acc
                (# i, Bool, Offset Word8 #)
_                                             -> Maybe i
forall a. Maybe a
Nothing
      where !endOfs :: Offset Word8
endOfs = Offset Word8
ofs Offset Word8 -> CountOf Word8 -> Offset Word8
forall ty. Offset ty -> CountOf ty -> Offset ty
`offsetPlusE` CountOf Word8
sz
    withPtr :: Ptr Word8 -> Offset Word8 -> Maybe i
withPtr Ptr Word8
addr Offset Word8
ofs =
        let negativeSign :: Bool
negativeSign = Ptr Word8 -> Offset Word8 -> Word8 -> Bool
forall container.
Indexable container Word8 =>
container -> Offset Word8 -> Word8 -> Bool
UTF8.expectAscii Ptr Word8
addr Offset Word8
ofs Word8
0x2d
            startOfs :: Offset Word8
startOfs     = if Bool
negativeSign then Offset Word8 -> Offset Word8
forall a. Enum a => a -> a
succ Offset Word8
ofs else Offset Word8
ofs
         in case i
-> Ptr Word8
-> Offset Word8
-> Offset Word8
-> (# i, Bool, Offset Word8 #)
forall acc.
(IntegralUpsize Word8 acc, Additive acc, Multiplicative acc,
 Integral acc) =>
acc
-> Ptr Word8
-> Offset Word8
-> Offset Word8
-> (# acc, Bool, Offset Word8 #)
decimalDigitsPtr i
0 Ptr Word8
addr Offset Word8
endOfs Offset Word8
startOfs of
                (# i
acc, Bool
True, Offset Word8
endOfs' #) | Offset Word8
endOfs' Offset Word8 -> Offset Word8 -> Bool
forall a. Ord a => a -> a -> Bool
> Offset Word8
startOfs -> i -> Maybe i
forall a. a -> Maybe a
Just (i -> Maybe i) -> i -> Maybe i
forall a b. (a -> b) -> a -> b
$! if Bool
negativeSign then i -> i
forall a. HasNegation a => a -> a
negate i
acc else i
acc
                (# i, Bool, Offset Word8 #)
_                                             -> Maybe i
forall a. Maybe a
Nothing
      where !endOfs :: Offset Word8
endOfs = Offset Word8
ofs Offset Word8 -> CountOf Word8 -> Offset Word8
forall ty. Offset ty -> CountOf ty -> Offset ty
`offsetPlusE` CountOf Word8
sz
{-# SPECIALISE readIntegral :: String -> Maybe Integer #-}
{-# SPECIALISE readIntegral :: String -> Maybe Int #-}

readInteger :: String -> Maybe Integer
readInteger :: String -> Maybe Integer
readInteger = String -> Maybe Integer
forall i.
(HasNegation i, IntegralUpsize Word8 i, Additive i,
 Multiplicative i, IsIntegral i) =>
String -> Maybe i
readIntegral

-- | Read a Natural from a String
--
-- Consume many digits until end of string.
readNatural :: String -> Maybe Natural
readNatural :: String -> Maybe Natural
readNatural String
str
    | CountOf Word8
sz CountOf Word8 -> CountOf Word8 -> Bool
forall a. Eq a => a -> a -> Bool
== CountOf Word8
0   = Maybe Natural
forall a. Maybe a
Nothing
    | Bool
otherwise = (Block Word8 -> Offset Word8 -> Maybe Natural)
-> (Ptr Word8 -> Offset Word8 -> ST Any (Maybe Natural))
-> String
-> Maybe Natural
forall a s.
(Block Word8 -> Offset Word8 -> a)
-> (Ptr Word8 -> Offset Word8 -> ST s a) -> String -> a
stringDewrap Block Word8 -> Offset Word8 -> Maybe Natural
withBa (\ptr :: Ptr Word8
ptr@(Ptr !Addr#
_) -> Maybe Natural -> ST Any (Maybe Natural)
forall (f :: * -> *) a. Applicative f => a -> f a
pure (Maybe Natural -> ST Any (Maybe Natural))
-> (Offset Word8 -> Maybe Natural)
-> Offset Word8
-> ST Any (Maybe Natural)
forall k (cat :: k -> k -> *) (b :: k) (c :: k) (a :: k).
Category cat =>
cat b c -> cat a b -> cat a c
. Ptr Word8 -> Offset Word8 -> Maybe Natural
withPtr Ptr Word8
ptr) String
str
  where
    !sz :: CountOf Word8
sz = String -> CountOf Word8
size String
str
    withBa :: Block Word8 -> Offset Word8 -> Maybe Natural
withBa Block Word8
ba Offset Word8
stringStart =
        case Natural
-> Block Word8
-> Offset Word8
-> Offset Word8
-> (# Natural, Bool, Offset Word8 #)
forall acc.
(IntegralUpsize Word8 acc, Additive acc, Multiplicative acc,
 Integral acc) =>
acc
-> Block Word8
-> Offset Word8
-> Offset Word8
-> (# acc, Bool, Offset Word8 #)
decimalDigitsBA Natural
0 Block Word8
ba Offset Word8
eofs Offset Word8
stringStart of
            (# Natural
acc, Bool
True, Offset Word8
endOfs #) | Offset Word8
endOfs Offset Word8 -> Offset Word8 -> Bool
forall a. Ord a => a -> a -> Bool
> Offset Word8
stringStart -> Natural -> Maybe Natural
forall a. a -> Maybe a
Just Natural
acc
            (# Natural, Bool, Offset Word8 #)
_                                              -> Maybe Natural
forall a. Maybe a
Nothing
      where eofs :: Offset Word8
eofs = Offset Word8
stringStart Offset Word8 -> CountOf Word8 -> Offset Word8
forall ty. Offset ty -> CountOf ty -> Offset ty
`offsetPlusE` CountOf Word8
sz
    withPtr :: Ptr Word8 -> Offset Word8 -> Maybe Natural
withPtr Ptr Word8
addr Offset Word8
stringStart =
        case Natural
-> Ptr Word8
-> Offset Word8
-> Offset Word8
-> (# Natural, Bool, Offset Word8 #)
forall acc.
(IntegralUpsize Word8 acc, Additive acc, Multiplicative acc,
 Integral acc) =>
acc
-> Ptr Word8
-> Offset Word8
-> Offset Word8
-> (# acc, Bool, Offset Word8 #)
decimalDigitsPtr Natural
0 Ptr Word8
addr Offset Word8
eofs Offset Word8
stringStart of
            (# Natural
acc, Bool
True, Offset Word8
endOfs #) | Offset Word8
endOfs Offset Word8 -> Offset Word8 -> Bool
forall a. Ord a => a -> a -> Bool
> Offset Word8
stringStart -> Natural -> Maybe Natural
forall a. a -> Maybe a
Just Natural
acc
            (# Natural, Bool, Offset Word8 #)
_                                              -> Maybe Natural
forall a. Maybe a
Nothing
      where eofs :: Offset Word8
eofs = Offset Word8
stringStart Offset Word8 -> CountOf Word8 -> Offset Word8
forall ty. Offset ty -> CountOf ty -> Offset ty
`offsetPlusE` CountOf Word8
sz

-- | Try to read a Double
readDouble :: String -> Maybe Double
readDouble :: String -> Maybe Double
readDouble String
s =
    String -> ReadFloatingCallback Double -> Maybe Double
forall a. String -> ReadFloatingCallback a -> Maybe a
readFloatingExact String
s (ReadFloatingCallback Double -> Maybe Double)
-> ReadFloatingCallback Double -> Maybe Double
forall a b. (a -> b) -> a -> b
$ \Bool
isNegative Natural
integral Word
floatingDigits Maybe Int
mExponant ->
        Double -> Maybe Double
forall a. a -> Maybe a
Just (Double -> Maybe Double) -> Double -> Maybe Double
forall a b. (a -> b) -> a -> b
$ Bool -> Double -> Double
forall a. HasNegation a => Bool -> a -> a
applySign Bool
isNegative (Double -> Double) -> Double -> Double
forall a b. (a -> b) -> a -> b
$ case (Word
floatingDigits, Maybe Int
mExponant) of
            (Word
0, Maybe Int
Nothing)              ->                         Natural -> Double
naturalToDouble Natural
integral
            (Word
0, Just Int
exponent)        -> Int -> Double -> Double
withExponant Int
exponent (Double -> Double) -> Double -> Double
forall a b. (a -> b) -> a -> b
$ Natural -> Double
naturalToDouble Natural
integral
            (Word
floating, Maybe Int
Nothing)       ->                         Word -> Double -> Double
forall a b.
(Divisible a, Integral b, Integral a, Num a) =>
b -> a -> a
applyFloating Word
floating (Double -> Double) -> Double -> Double
forall a b. (a -> b) -> a -> b
$ Natural -> Double
naturalToDouble Natural
integral
            (Word
floating, Just Int
exponent) -> Int -> Double -> Double
withExponant Int
exponent (Double -> Double) -> Double -> Double
forall a b. (a -> b) -> a -> b
$ Word -> Double -> Double
forall a b.
(Divisible a, Integral b, Integral a, Num a) =>
b -> a -> a
applyFloating Word
floating (Double -> Double) -> Double -> Double
forall a b. (a -> b) -> a -> b
$ Natural -> Double
naturalToDouble Natural
integral
  where
    applySign :: Bool -> a -> a
applySign Bool
True = a -> a
forall a. HasNegation a => a -> a
negate
    applySign Bool
False = a -> a
forall k (cat :: k -> k -> *) (a :: k). Category cat => cat a a
id
    withExponant :: Int -> Double -> Double
withExponant Int
e Double
v = Double
v Double -> Double -> Double
forall a. Multiplicative a => a -> a -> a
* Double -> Int -> Double
doubleExponant Double
10 Int
e
    applyFloating :: b -> a -> a
applyFloating b
digits a
n = a
n a -> a -> a
forall a. Divisible a => a -> a -> a
/ (a
10 a -> b -> a
forall a b. (Num a, Integral b) => a -> b -> a
Prelude.^ b
digits)

-- | Try to read a floating number as a Rational
--
-- Note that for safety reason, only exponent between -10000 and 10000 is allowed
-- as otherwise DoS/OOM is very likely. if you don't want this behavior,
-- switching to a scientific type (not provided yet) that represent the
-- exponent separately is the advised solution.
readRational :: String -> Maybe Prelude.Rational
readRational :: String -> Maybe Rational
readRational String
s =
    String -> ReadFloatingCallback Rational -> Maybe Rational
forall a. String -> ReadFloatingCallback a -> Maybe a
readFloatingExact String
s (ReadFloatingCallback Rational -> Maybe Rational)
-> ReadFloatingCallback Rational -> Maybe Rational
forall a b. (a -> b) -> a -> b
$ \Bool
isNegative Natural
integral Word
floatingDigits Maybe Int
mExponant ->
        case Maybe Int
mExponant of
            Just Int
exponent
                | Int
exponent Int -> Int -> Bool
forall a. Ord a => a -> a -> Bool
< -Int
10000 Bool -> Bool -> Bool
|| Int
exponent Int -> Int -> Bool
forall a. Ord a => a -> a -> Bool
> Int
10000 -> Maybe Rational
forall a. Maybe a
Nothing
                | Bool
otherwise                             -> Rational -> Maybe Rational
forall a. a -> Maybe a
Just (Rational -> Maybe Rational) -> Rational -> Maybe Rational
forall a b. (a -> b) -> a -> b
$ Bool -> Natural -> Integer
forall b a. (HasNegation b, IntegralUpsize a b) => Bool -> a -> b
modF Bool
isNegative Natural
integral Integer -> Integer -> Rational
forall a. Integral a => a -> a -> Ratio a
% (Integer
10 Integer -> Int -> Integer
forall a b. (Num a, Integral b) => a -> b -> a
Prelude.^ (Word -> Int
forall source destination.
Cast source destination =>
source -> destination
cast Word
floatingDigits Int -> Int -> Difference Int
forall a. Subtractive a => a -> a -> Difference a
- Int
exponent))
            Maybe Int
Nothing                                     -> Rational -> Maybe Rational
forall a. a -> Maybe a
Just (Rational -> Maybe Rational) -> Rational -> Maybe Rational
forall a b. (a -> b) -> a -> b
$ Bool -> Natural -> Integer
forall b a. (HasNegation b, IntegralUpsize a b) => Bool -> a -> b
modF Bool
isNegative Natural
integral Integer -> Integer -> Rational
forall a. Integral a => a -> a -> Ratio a
% (Integer
10 Integer -> Word -> Integer
forall a b. (Num a, Integral b) => a -> b -> a
Prelude.^ Word
floatingDigits)
  where
    modF :: Bool -> a -> b
modF Bool
True  = b -> b
forall a. HasNegation a => a -> a
negate (b -> b) -> (a -> b) -> a -> b
forall k (cat :: k -> k -> *) (b :: k) (c :: k) (a :: k).
Category cat =>
cat b c -> cat a b -> cat a c
. a -> b
forall a b. IntegralUpsize a b => a -> b
integralUpsize
    modF Bool
False = a -> b
forall a b. IntegralUpsize a b => a -> b
integralUpsize


type ReadFloatingCallback a = Bool      -- sign
                           -> Natural   -- integral part
                           -> Word      -- number of digits in floating section
                           -> Maybe Int -- optional integer representing exponent in base 10
                           -> Maybe a

-- | Read an Floating like number of the form:
--
--   [ '-' ] <numbers> [ '.' <numbers> ] [ ( 'e' | 'E' ) [ '-' ] <number> ]
--
-- Call a function with:
--
-- * A boolean representing if the number is negative
-- * The digits part represented as a single natural number (123.456 is represented as 123456)
-- * The number of digits in the fractional part (e.g. 123.456 => 3)
-- * The exponent if any
--
-- The code is structured as a simple state machine that:
--
-- * Optionally Consume a '-' sign
-- * Consume number for the integral part
-- * Optionally
--   * Consume '.'
--   * Consume remaining digits if not already end of string
-- * Optionally Consume a 'e' or 'E' follow by an optional '-' and a number
--
readFloatingExact :: String -> ReadFloatingCallback a -> Maybe a
readFloatingExact :: String -> ReadFloatingCallback a -> Maybe a
readFloatingExact String
str ReadFloatingCallback a
f
    | CountOf Word8
sz CountOf Word8 -> CountOf Word8 -> Bool
forall a. Eq a => a -> a -> Bool
== CountOf Word8
0   = Maybe a
forall a. Maybe a
Nothing
    | Bool
otherwise = (Block Word8 -> Offset Word8 -> Maybe a)
-> (Ptr Word8 -> Offset Word8 -> ST Any (Maybe a))
-> String
-> Maybe a
forall a s.
(Block Word8 -> Offset Word8 -> a)
-> (Ptr Word8 -> Offset Word8 -> ST s a) -> String -> a
stringDewrap Block Word8 -> Offset Word8 -> Maybe a
withBa Ptr Word8 -> Offset Word8 -> ST Any (Maybe a)
withPtr String
str
  where
    !sz :: CountOf Word8
sz = String -> CountOf Word8
size String
str

    withBa :: Block Word8 -> Offset Word8 -> Maybe a
withBa Block Word8
ba Offset Word8
stringStart =
        let !isNegative :: Bool
isNegative = Block Word8 -> Offset Word8 -> Word8 -> Bool
forall container.
Indexable container Word8 =>
container -> Offset Word8 -> Word8 -> Bool
UTF8.expectAscii Block Word8
ba Offset Word8
stringStart Word8
0x2d
         in Bool -> Offset Word8 -> Maybe a
consumeIntegral Bool
isNegative (if Bool
isNegative then Offset Word8
stringStartOffset Word8 -> Offset Word8 -> Offset Word8
forall a. Additive a => a -> a -> a
+Offset Word8
1 else Offset Word8
stringStart)
      where
        eofs :: Offset Word8
eofs = Offset Word8
stringStart Offset Word8 -> CountOf Word8 -> Offset Word8
forall ty. Offset ty -> CountOf ty -> Offset ty
`offsetPlusE` CountOf Word8
sz
        consumeIntegral :: Bool -> Offset Word8 -> Maybe a
consumeIntegral !Bool
isNegative Offset Word8
startOfs =
            case Natural
-> Block Word8
-> Offset Word8
-> Offset Word8
-> (# Natural, Bool, Offset Word8 #)
forall acc.
(IntegralUpsize Word8 acc, Additive acc, Multiplicative acc,
 Integral acc) =>
acc
-> Block Word8
-> Offset Word8
-> Offset Word8
-> (# acc, Bool, Offset Word8 #)
decimalDigitsBA Natural
0 Block Word8
ba Offset Word8
eofs Offset Word8
startOfs of
                (# Natural
acc, Bool
True , Offset Word8
endOfs #) | Offset Word8
endOfs Offset Word8 -> Offset Word8 -> Bool
forall a. Ord a => a -> a -> Bool
> Offset Word8
startOfs -> ReadFloatingCallback a
f Bool
isNegative Natural
acc Word
0 Maybe Int
forall a. Maybe a
Nothing -- end of stream and no '.'
                (# Natural
acc, Bool
False, Offset Word8
endOfs #) | Offset Word8
endOfs Offset Word8 -> Offset Word8 -> Bool
forall a. Ord a => a -> a -> Bool
> Offset Word8
startOfs ->
                    if Block Word8 -> Offset Word8 -> Word8 -> Bool
forall container.
Indexable container Word8 =>
container -> Offset Word8 -> Word8 -> Bool
UTF8.expectAscii Block Word8
ba Offset Word8
endOfs Word8
0x2e
                        then Bool -> Natural -> Offset Word8 -> Maybe a
consumeFloat Bool
isNegative Natural
acc (Offset Word8
endOfs Offset Word8 -> Offset Word8 -> Offset Word8
forall a. Additive a => a -> a -> a
+ Offset Word8
1)
                        else Bool -> Natural -> Word -> Offset Word8 -> Maybe a
consumeExponant Bool
isNegative Natural
acc Word
0 Offset Word8
endOfs
                (# Natural, Bool, Offset Word8 #)
_                                            -> Maybe a
forall a. Maybe a
Nothing

        consumeFloat :: Bool -> Natural -> Offset Word8 -> Maybe a
consumeFloat Bool
isNegative Natural
integral Offset Word8
startOfs =
            case Natural
-> Block Word8
-> Offset Word8
-> Offset Word8
-> (# Natural, Bool, Offset Word8 #)
forall acc.
(IntegralUpsize Word8 acc, Additive acc, Multiplicative acc,
 Integral acc) =>
acc
-> Block Word8
-> Offset Word8
-> Offset Word8
-> (# acc, Bool, Offset Word8 #)
decimalDigitsBA Natural
integral Block Word8
ba Offset Word8
eofs Offset Word8
startOfs of
                (# Natural
acc, Bool
True, Offset Word8
endOfs #) | Offset Word8
endOfs Offset Word8 -> Offset Word8 -> Bool
forall a. Ord a => a -> a -> Bool
> Offset Word8
startOfs -> let (CountOf !Int
diff) = Offset Word8
endOfs Offset Word8 -> Offset Word8 -> Difference (Offset Word8)
forall a. Subtractive a => a -> a -> Difference a
- Offset Word8
startOfs
                                                                in ReadFloatingCallback a
f Bool
isNegative Natural
acc (Int -> Word
forall source destination.
Cast source destination =>
source -> destination
cast Int
diff) Maybe Int
forall a. Maybe a
Nothing
                (# Natural
acc, Bool
False, Offset Word8
endOfs #) | Offset Word8
endOfs Offset Word8 -> Offset Word8 -> Bool
forall a. Ord a => a -> a -> Bool
> Offset Word8
startOfs -> let (CountOf !Int
diff) = Offset Word8
endOfs Offset Word8 -> Offset Word8 -> Difference (Offset Word8)
forall a. Subtractive a => a -> a -> Difference a
- Offset Word8
startOfs
                                                                in Bool -> Natural -> Word -> Offset Word8 -> Maybe a
consumeExponant Bool
isNegative Natural
acc (Int -> Word
forall source destination.
Cast source destination =>
source -> destination
cast Int
diff) Offset Word8
endOfs
                (# Natural, Bool, Offset Word8 #)
_                                           -> Maybe a
forall a. Maybe a
Nothing

        consumeExponant :: Bool -> Natural -> Word -> Offset Word8 -> Maybe a
consumeExponant !Bool
isNegative !Natural
integral !Word
floatingDigits !Offset Word8
startOfs
            | Offset Word8
startOfs Offset Word8 -> Offset Word8 -> Bool
forall a. Eq a => a -> a -> Bool
== Offset Word8
eofs = ReadFloatingCallback a
f Bool
isNegative Natural
integral Word
floatingDigits Maybe Int
forall a. Maybe a
Nothing
            | Bool
otherwise        =
                -- consume 'E' or 'e'
                case Block Word8 -> Offset Word8 -> StepASCII
forall container.
Indexable container Word8 =>
container -> Offset Word8 -> StepASCII
UTF8.nextAscii Block Word8
ba Offset Word8
startOfs of
                    StepASCII Word8
0x45 -> Offset Word8 -> Maybe a
consumeExponantSign (Offset Word8
startOfsOffset Word8 -> Offset Word8 -> Offset Word8
forall a. Additive a => a -> a -> a
+Offset Word8
1)
                    StepASCII Word8
0x65 -> Offset Word8 -> Maybe a
consumeExponantSign (Offset Word8
startOfsOffset Word8 -> Offset Word8 -> Offset Word8
forall a. Additive a => a -> a -> a
+Offset Word8
1)
                    StepASCII
_              -> Maybe a
forall a. Maybe a
Nothing
          where
            consumeExponantSign :: Offset Word8 -> Maybe a
consumeExponantSign Offset Word8
ofs
                | Offset Word8
ofs Offset Word8 -> Offset Word8 -> Bool
forall a. Eq a => a -> a -> Bool
== Offset Word8
eofs = Maybe a
forall a. Maybe a
Nothing
                | Bool
otherwise   = let exponentNegative :: Bool
exponentNegative = Block Word8 -> Offset Word8 -> Word8 -> Bool
forall container.
Indexable container Word8 =>
container -> Offset Word8 -> Word8 -> Bool
UTF8.expectAscii Block Word8
ba Offset Word8
ofs Word8
0x2d
                                 in Bool -> Offset Word8 -> Maybe a
consumeExponantNumber Bool
exponentNegative (if Bool
exponentNegative then Offset Word8
ofs Offset Word8 -> Offset Word8 -> Offset Word8
forall a. Additive a => a -> a -> a
+ Offset Word8
1 else Offset Word8
ofs)

            consumeExponantNumber :: Bool -> Offset Word8 -> Maybe a
consumeExponantNumber Bool
exponentNegative Offset Word8
ofs =
                case Int
-> Block Word8
-> Offset Word8
-> Offset Word8
-> (# Int, Bool, Offset Word8 #)
forall acc.
(IntegralUpsize Word8 acc, Additive acc, Multiplicative acc,
 Integral acc) =>
acc
-> Block Word8
-> Offset Word8
-> Offset Word8
-> (# acc, Bool, Offset Word8 #)
decimalDigitsBA Int
0 Block Word8
ba Offset Word8
eofs Offset Word8
ofs of
                    (# Int
acc, Bool
True, Offset Word8
endOfs #) | Offset Word8
endOfs Offset Word8 -> Offset Word8 -> Bool
forall a. Ord a => a -> a -> Bool
> Offset Word8
ofs -> ReadFloatingCallback a
f Bool
isNegative Natural
integral Word
floatingDigits (Int -> Maybe Int
forall a. a -> Maybe a
Just (Int -> Maybe Int) -> Int -> Maybe Int
forall a b. (a -> b) -> a -> b
$! if Bool
exponentNegative then Int -> Int
forall a. HasNegation a => a -> a
negate Int
acc else Int
acc)
                    (# Int, Bool, Offset Word8 #)
_                                      -> Maybe a
forall a. Maybe a
Nothing
    withPtr :: Ptr Word8 -> Offset Word8 -> ST Any (Maybe a)
withPtr ptr :: Ptr Word8
ptr@(Ptr !Addr#
_) Offset Word8
stringStart = Maybe a -> ST Any (Maybe a)
forall (f :: * -> *) a. Applicative f => a -> f a
pure (Maybe a -> ST Any (Maybe a)) -> Maybe a -> ST Any (Maybe a)
forall a b. (a -> b) -> a -> b
$
        let !isNegative :: Bool
isNegative = Ptr Word8 -> Offset Word8 -> Word8 -> Bool
forall container.
Indexable container Word8 =>
container -> Offset Word8 -> Word8 -> Bool
UTF8.expectAscii Ptr Word8
ptr Offset Word8
stringStart Word8
0x2d
         in Bool -> Offset Word8 -> Maybe a
consumeIntegral Bool
isNegative (if Bool
isNegative then Offset Word8
stringStartOffset Word8 -> Offset Word8 -> Offset Word8
forall a. Additive a => a -> a -> a
+Offset Word8
1 else Offset Word8
stringStart)
      where
        eofs :: Offset Word8
eofs = Offset Word8
stringStart Offset Word8 -> CountOf Word8 -> Offset Word8
forall ty. Offset ty -> CountOf ty -> Offset ty
`offsetPlusE` CountOf Word8
sz
        consumeIntegral :: Bool -> Offset Word8 -> Maybe a
consumeIntegral !Bool
isNegative Offset Word8
startOfs =
            case Natural
-> Ptr Word8
-> Offset Word8
-> Offset Word8
-> (# Natural, Bool, Offset Word8 #)
forall acc.
(IntegralUpsize Word8 acc, Additive acc, Multiplicative acc,
 Integral acc) =>
acc
-> Ptr Word8
-> Offset Word8
-> Offset Word8
-> (# acc, Bool, Offset Word8 #)
decimalDigitsPtr Natural
0 Ptr Word8
ptr Offset Word8
eofs Offset Word8
startOfs of
                (# Natural
acc, Bool
True , Offset Word8
endOfs #) | Offset Word8
endOfs Offset Word8 -> Offset Word8 -> Bool
forall a. Ord a => a -> a -> Bool
> Offset Word8
startOfs -> ReadFloatingCallback a
f Bool
isNegative Natural
acc Word
0 Maybe Int
forall a. Maybe a
Nothing -- end of stream and no '.'
                (# Natural
acc, Bool
False, Offset Word8
endOfs #) | Offset Word8
endOfs Offset Word8 -> Offset Word8 -> Bool
forall a. Ord a => a -> a -> Bool
> Offset Word8
startOfs ->
                    if Ptr Word8 -> Offset Word8 -> Word8 -> Bool
forall container.
Indexable container Word8 =>
container -> Offset Word8 -> Word8 -> Bool
UTF8.expectAscii Ptr Word8
ptr Offset Word8
endOfs Word8
0x2e
                        then Bool -> Natural -> Offset Word8 -> Maybe a
consumeFloat Bool
isNegative Natural
acc (Offset Word8
endOfs Offset Word8 -> Offset Word8 -> Offset Word8
forall a. Additive a => a -> a -> a
+ Offset Word8
1)
                        else Bool -> Natural -> Word -> Offset Word8 -> Maybe a
consumeExponant Bool
isNegative Natural
acc Word
0 Offset Word8
endOfs
                (# Natural, Bool, Offset Word8 #)
_                                            -> Maybe a
forall a. Maybe a
Nothing

        consumeFloat :: Bool -> Natural -> Offset Word8 -> Maybe a
consumeFloat Bool
isNegative Natural
integral Offset Word8
startOfs =
            case Natural
-> Ptr Word8
-> Offset Word8
-> Offset Word8
-> (# Natural, Bool, Offset Word8 #)
forall acc.
(IntegralUpsize Word8 acc, Additive acc, Multiplicative acc,
 Integral acc) =>
acc
-> Ptr Word8
-> Offset Word8
-> Offset Word8
-> (# acc, Bool, Offset Word8 #)
decimalDigitsPtr Natural
integral Ptr Word8
ptr Offset Word8
eofs Offset Word8
startOfs of
                (# Natural
acc, Bool
True, Offset Word8
endOfs #) | Offset Word8
endOfs Offset Word8 -> Offset Word8 -> Bool
forall a. Ord a => a -> a -> Bool
> Offset Word8
startOfs -> let (CountOf !Int
diff) = Offset Word8
endOfs Offset Word8 -> Offset Word8 -> Difference (Offset Word8)
forall a. Subtractive a => a -> a -> Difference a
- Offset Word8
startOfs
                                                                in ReadFloatingCallback a
f Bool
isNegative Natural
acc (Int -> Word
forall source destination.
Cast source destination =>
source -> destination
cast Int
diff) Maybe Int
forall a. Maybe a
Nothing
                (# Natural
acc, Bool
False, Offset Word8
endOfs #) | Offset Word8
endOfs Offset Word8 -> Offset Word8 -> Bool
forall a. Ord a => a -> a -> Bool
> Offset Word8
startOfs -> let (CountOf !Int
diff) = Offset Word8
endOfs Offset Word8 -> Offset Word8 -> Difference (Offset Word8)
forall a. Subtractive a => a -> a -> Difference a
- Offset Word8
startOfs
                                                                in Bool -> Natural -> Word -> Offset Word8 -> Maybe a
consumeExponant Bool
isNegative Natural
acc (Int -> Word
forall source destination.
Cast source destination =>
source -> destination
cast Int
diff) Offset Word8
endOfs
                (# Natural, Bool, Offset Word8 #)
_                                           -> Maybe a
forall a. Maybe a
Nothing

        consumeExponant :: Bool -> Natural -> Word -> Offset Word8 -> Maybe a
consumeExponant !Bool
isNegative !Natural
integral !Word
floatingDigits !Offset Word8
startOfs
            | Offset Word8
startOfs Offset Word8 -> Offset Word8 -> Bool
forall a. Eq a => a -> a -> Bool
== Offset Word8
eofs = ReadFloatingCallback a
f Bool
isNegative Natural
integral Word
floatingDigits Maybe Int
forall a. Maybe a
Nothing
            | Bool
otherwise        =
                -- consume 'E' or 'e'
                case Ptr Word8 -> Offset Word8 -> StepASCII
forall container.
Indexable container Word8 =>
container -> Offset Word8 -> StepASCII
UTF8.nextAscii Ptr Word8
ptr Offset Word8
startOfs of
                    StepASCII Word8
0x45 -> Offset Word8 -> Maybe a
consumeExponantSign (Offset Word8
startOfsOffset Word8 -> Offset Word8 -> Offset Word8
forall a. Additive a => a -> a -> a
+Offset Word8
1)
                    StepASCII Word8
0x65 -> Offset Word8 -> Maybe a
consumeExponantSign (Offset Word8
startOfsOffset Word8 -> Offset Word8 -> Offset Word8
forall a. Additive a => a -> a -> a
+Offset Word8
1)
                    StepASCII
_              -> Maybe a
forall a. Maybe a
Nothing
          where
            consumeExponantSign :: Offset Word8 -> Maybe a
consumeExponantSign Offset Word8
ofs
                | Offset Word8
ofs Offset Word8 -> Offset Word8 -> Bool
forall a. Eq a => a -> a -> Bool
== Offset Word8
eofs = Maybe a
forall a. Maybe a
Nothing
                | Bool
otherwise   = let exponentNegative :: Bool
exponentNegative = Ptr Word8 -> Offset Word8 -> Word8 -> Bool
forall container.
Indexable container Word8 =>
container -> Offset Word8 -> Word8 -> Bool
UTF8.expectAscii Ptr Word8
ptr Offset Word8
ofs Word8
0x2d
                                 in Bool -> Offset Word8 -> Maybe a
consumeExponantNumber Bool
exponentNegative (if Bool
exponentNegative then Offset Word8
ofs Offset Word8 -> Offset Word8 -> Offset Word8
forall a. Additive a => a -> a -> a
+ Offset Word8
1 else Offset Word8
ofs)

            consumeExponantNumber :: Bool -> Offset Word8 -> Maybe a
consumeExponantNumber Bool
exponentNegative Offset Word8
ofs =
                case Int
-> Ptr Word8
-> Offset Word8
-> Offset Word8
-> (# Int, Bool, Offset Word8 #)
forall acc.
(IntegralUpsize Word8 acc, Additive acc, Multiplicative acc,
 Integral acc) =>
acc
-> Ptr Word8
-> Offset Word8
-> Offset Word8
-> (# acc, Bool, Offset Word8 #)
decimalDigitsPtr Int
0 Ptr Word8
ptr Offset Word8
eofs Offset Word8
ofs of
                    (# Int
acc, Bool
True, Offset Word8
endOfs #) | Offset Word8
endOfs Offset Word8 -> Offset Word8 -> Bool
forall a. Ord a => a -> a -> Bool
> Offset Word8
ofs -> ReadFloatingCallback a
f Bool
isNegative Natural
integral Word
floatingDigits (Int -> Maybe Int
forall a. a -> Maybe a
Just (Int -> Maybe Int) -> Int -> Maybe Int
forall a b. (a -> b) -> a -> b
$! if Bool
exponentNegative then Int -> Int
forall a. HasNegation a => a -> a
negate Int
acc else Int
acc)
                    (# Int, Bool, Offset Word8 #)
_                                      -> Maybe a
forall a. Maybe a
Nothing

-- | Take decimal digits and accumulate it in `acc`
--
-- The loop starts at the offset specified and finish either when:
--
-- * It reach the end of the string
-- * It reach a non-ASCII character
-- * It reach an ASCII character that is not a digit (0 to 9)
--
-- Otherwise each iterations:
--
-- * Transform the ASCII digits into a number
-- * scale the accumulator by 10
-- * Add the number (between 0 and 9) to the accumulator
--
-- It then returns:
--
-- * The new accumulated value
-- * Whether it stop by end of string or not
-- * The end offset when the loop stopped
--
-- If end offset == start offset then no digits have been consumed by
-- this function
decimalDigitsBA :: (IntegralUpsize Word8 acc, Additive acc, Multiplicative acc, Integral acc)
                => acc
                -> Block Word8
                -> Offset Word8 -- end offset
                -> Offset Word8 -- start offset
                -> (# acc, Bool, Offset Word8 #)
decimalDigitsBA :: acc
-> Block Word8
-> Offset Word8
-> Offset Word8
-> (# acc, Bool, Offset Word8 #)
decimalDigitsBA acc
startAcc Block Word8
ba !Offset Word8
endOfs !Offset Word8
startOfs = acc -> Offset Word8 -> (# acc, Bool, Offset Word8 #)
loop acc
startAcc Offset Word8
startOfs
  where
    loop :: acc -> Offset Word8 -> (# acc, Bool, Offset Word8 #)
loop !acc
acc !Offset Word8
ofs
        | Offset Word8
ofs Offset Word8 -> Offset Word8 -> Bool
forall a. Eq a => a -> a -> Bool
== Offset Word8
endOfs = (# acc
acc, Bool
True, Offset Word8
ofs #)
        | Bool
otherwise     =
            case Block Word8 -> Offset Word8 -> StepDigit
forall container.
Indexable container Word8 =>
container -> Offset Word8 -> StepDigit
UTF8.nextAsciiDigit Block Word8
ba Offset Word8
ofs of
                sg :: StepDigit
sg@(StepDigit Word8
d) | StepDigit -> Bool
isValidStepDigit StepDigit
sg -> acc -> Offset Word8 -> (# acc, Bool, Offset Word8 #)
loop (acc
10 acc -> acc -> acc
forall a. Multiplicative a => a -> a -> a
* acc
acc acc -> acc -> acc
forall a. Additive a => a -> a -> a
+ Word8 -> acc
forall a b. IntegralUpsize a b => a -> b
integralUpsize Word8
d) (Offset Word8 -> Offset Word8
forall a. Enum a => a -> a
succ Offset Word8
ofs)
                                 | Bool
otherwise           -> (# acc
acc, Bool
False, Offset Word8
ofs #)
{-# SPECIALIZE decimalDigitsBA :: Integer -> Block Word8 -> Offset Word8 -> Offset Word8 -> (# Integer, Bool, Offset Word8 #) #-}
{-# SPECIALIZE decimalDigitsBA :: Natural -> Block Word8 -> Offset Word8 -> Offset Word8 -> (# Natural, Bool, Offset Word8 #) #-}
{-# SPECIALIZE decimalDigitsBA :: Int -> Block Word8 -> Offset Word8 -> Offset Word8 -> (# Int, Bool, Offset Word8 #) #-}
{-# SPECIALIZE decimalDigitsBA :: Word -> Block Word8 -> Offset Word8 -> Offset Word8 -> (# Word, Bool, Offset Word8 #) #-}

-- | same as decimalDigitsBA specialized for ptr #
decimalDigitsPtr :: (IntegralUpsize Word8 acc, Additive acc, Multiplicative acc, Integral acc)
                 => acc
                 -> Ptr Word8
                 -> Offset Word8 -- end offset
                 -> Offset Word8 -- start offset
                 -> (# acc, Bool, Offset Word8 #)
decimalDigitsPtr :: acc
-> Ptr Word8
-> Offset Word8
-> Offset Word8
-> (# acc, Bool, Offset Word8 #)
decimalDigitsPtr acc
startAcc Ptr Word8
ptr !Offset Word8
endOfs !Offset Word8
startOfs = acc -> Offset Word8 -> (# acc, Bool, Offset Word8 #)
loop acc
startAcc Offset Word8
startOfs
  where
    loop :: acc -> Offset Word8 -> (# acc, Bool, Offset Word8 #)
loop !acc
acc !Offset Word8
ofs
        | Offset Word8
ofs Offset Word8 -> Offset Word8 -> Bool
forall a. Eq a => a -> a -> Bool
== Offset Word8
endOfs = (# acc
acc, Bool
True, Offset Word8
ofs #)
        | Bool
otherwise     =
            case Ptr Word8 -> Offset Word8 -> StepDigit
forall container.
Indexable container Word8 =>
container -> Offset Word8 -> StepDigit
UTF8.nextAsciiDigit Ptr Word8
ptr Offset Word8
ofs of
                sg :: StepDigit
sg@(StepDigit Word8
d) | StepDigit -> Bool
isValidStepDigit StepDigit
sg -> acc -> Offset Word8 -> (# acc, Bool, Offset Word8 #)
loop (acc
10 acc -> acc -> acc
forall a. Multiplicative a => a -> a -> a
* acc
acc acc -> acc -> acc
forall a. Additive a => a -> a -> a
+ Word8 -> acc
forall a b. IntegralUpsize a b => a -> b
integralUpsize Word8
d) (Offset Word8 -> Offset Word8
forall a. Enum a => a -> a
succ Offset Word8
ofs)
                                 | Bool
otherwise           -> (# acc
acc, Bool
False, Offset Word8
ofs #)
{-# SPECIALIZE decimalDigitsPtr :: Integer -> Ptr Word8 -> Offset Word8 -> Offset Word8 -> (# Integer, Bool, Offset Word8 #) #-}
{-# SPECIALIZE decimalDigitsPtr :: Natural -> Ptr Word8 -> Offset Word8 -> Offset Word8 -> (# Natural, Bool, Offset Word8 #) #-}
{-# SPECIALIZE decimalDigitsPtr :: Int -> Ptr Word8 -> Offset Word8 -> Offset Word8 -> (# Int, Bool, Offset Word8 #) #-}
{-# SPECIALIZE decimalDigitsPtr :: Word -> Ptr Word8 -> Offset Word8 -> Offset Word8 -> (# Word, Bool, Offset Word8 #) #-}

-- | Convert a 'String' 'Char' by 'Char' using a case mapping function.
caseConvert :: (Char7 -> Char7) -> (Char -> CM) -> String -> String
caseConvert :: (Char7 -> Char7) -> (Char -> CM) -> String -> String
caseConvert Char7 -> Char7
opASCII Char -> CM
op s :: String
s@(String UArray Word8
arr) = (forall s. ST s String) -> String
forall a. (forall s. ST s a) -> a
runST ((forall s. ST s String) -> String)
-> (forall s. ST s String) -> String
forall a b. (a -> b) -> a -> b
$ do
  MutableBlock Word8 s
mba <- CountOf Word8 -> ST s (MutableBlock Word8 (PrimState (ST s)))
forall (prim :: * -> *) ty.
(PrimMonad prim, PrimType ty) =>
CountOf ty -> prim (MutableBlock ty (PrimState prim))
MBLK.new CountOf Word8
iLen
  CountOf Word8
nL <- (Block Word8 -> ST s (CountOf Word8))
-> (FinalPtr Word8 -> ST s (CountOf Word8))
-> UArray Word8
-> ST s (CountOf Word8)
forall (prim :: * -> *) ty a.
PrimMonad prim =>
(Block ty -> prim a)
-> (FinalPtr ty -> prim a) -> UArray ty -> prim a
C.onBackendPrim
        (\Block Word8
blk  -> MutableBlock Word8 (PrimState (ST s))
-> Block Word8
-> Offset Word8
-> Offset Word8
-> ST s (CountOf Word8)
forall container (prim :: * -> *).
(Indexable container Word8, PrimMonad prim) =>
MutableBlock Word8 (PrimState prim)
-> container
-> Offset Word8
-> Offset Word8
-> prim (CountOf Word8)
go MutableBlock Word8 s
MutableBlock Word8 (PrimState (ST s))
mba Block Word8
blk (Int -> Offset Word8
forall ty. Int -> Offset ty
Offset Int
0) Offset Word8
start)
        (\FinalPtr Word8
fptr -> FinalPtr Word8
-> (Ptr Word8 -> ST s (CountOf Word8)) -> ST s (CountOf Word8)
forall (prim :: * -> *) p a.
PrimMonad prim =>
FinalPtr p -> (Ptr p -> prim a) -> prim a
withFinalPtr FinalPtr Word8
fptr ((Ptr Word8 -> ST s (CountOf Word8)) -> ST s (CountOf Word8))
-> (Ptr Word8 -> ST s (CountOf Word8)) -> ST s (CountOf Word8)
forall a b. (a -> b) -> a -> b
$ \Ptr Word8
ptr -> MutableBlock Word8 (PrimState (ST s))
-> Ptr Word8
-> Offset Word8
-> Offset Word8
-> ST s (CountOf Word8)
forall container (prim :: * -> *).
(Indexable container Word8, PrimMonad prim) =>
MutableBlock Word8 (PrimState prim)
-> container
-> Offset Word8
-> Offset Word8
-> prim (CountOf Word8)
go MutableBlock Word8 s
MutableBlock Word8 (PrimState (ST s))
mba Ptr Word8
ptr (Int -> Offset Word8
forall ty. Int -> Offset ty
Offset Int
0) Offset Word8
start)
        UArray Word8
arr
  MutableString s -> ST s String
forall (prim :: * -> *).
PrimMonad prim =>
MutableString (PrimState prim) -> prim String
freeze (MutableString s -> ST s String)
-> (MUArray Word8 s -> MutableString s)
-> MUArray Word8 s
-> ST s String
forall k (cat :: k -> k -> *) (b :: k) (c :: k) (a :: k).
Category cat =>
cat b c -> cat a b -> cat a c
. MUArray Word8 s -> MutableString s
forall st. MUArray Word8 st -> MutableString st
MutableString (MUArray Word8 s -> ST s String) -> MUArray Word8 s -> ST s String
forall a b. (a -> b) -> a -> b
$ Offset Word8
-> CountOf Word8 -> MUArrayBackend Word8 s -> MUArray Word8 s
forall ty st.
Offset ty -> CountOf ty -> MUArrayBackend ty st -> MUArray ty st
MVec.MUArray Offset Word8
0 CountOf Word8
nL (MutableBlock Word8 s -> MUArrayBackend Word8 s
forall ty st. MutableBlock ty st -> MUArrayBackend ty st
C.MUArrayMBA MutableBlock Word8 s
mba)
  where
    !(C.ValidRange Offset Word8
start Offset Word8
end) = UArray Word8 -> ValidRange Word8
forall ty. UArray ty -> ValidRange ty
C.offsetsValidRange UArray Word8
arr
    !iLen :: CountOf Word8
iLen = CountOf Word8
1 CountOf Word8 -> CountOf Word8 -> CountOf Word8
forall a. Additive a => a -> a -> a
+ UArray Word8 -> CountOf Word8
forall ty. UArray ty -> CountOf ty
C.length UArray Word8
arr
    go :: (Indexable container Word8, PrimMonad prim)
       => MutableBlock Word8 (PrimState prim)
       -> container
       -> Offset Word8
       -> Offset Word8
       -> prim (CountOf Word8)
    go :: MutableBlock Word8 (PrimState prim)
-> container
-> Offset Word8
-> Offset Word8
-> prim (CountOf Word8)
go !MutableBlock Word8 (PrimState prim)
dst !container
src = MutableBlock Word8 (PrimState prim)
-> CountOf Word8
-> CountOf Word8
-> Offset Word8
-> Offset Word8
-> prim (CountOf Word8)
loop MutableBlock Word8 (PrimState prim)
dst CountOf Word8
iLen CountOf Word8
0
      where
        eSize :: Char -> CountOf Word8
eSize !Char
e = if Char
e Char -> Char -> Bool
forall a. Eq a => a -> a -> Bool
== Char
'\0' then CountOf Word8
0 else Int -> CountOf Word8
charToBytes (Char -> Int
forall a. Enum a => a -> Int
fromEnum Char
e)
        loop :: MutableBlock Word8 (PrimState prim)
-> CountOf Word8
-> CountOf Word8
-> Offset Word8
-> Offset Word8
-> prim (CountOf Word8)
loop !MutableBlock Word8 (PrimState prim)
dst !CountOf Word8
allocLen !CountOf Word8
nLen !Offset Word8
dstIdx !Offset Word8
srcIdx
          | Offset Word8
srcIdx Offset Word8 -> Offset Word8 -> Bool
forall a. Eq a => a -> a -> Bool
== Offset Word8
end    = CountOf Word8 -> prim (CountOf Word8)
forall (m :: * -> *) a. Monad m => a -> m a
return CountOf Word8
nLen
          | CountOf Word8
nLen CountOf Word8 -> CountOf Word8 -> Bool
forall a. Eq a => a -> a -> Bool
== CountOf Word8
allocLen = prim (CountOf Word8)
realloc
          | StepASCII -> Bool
headerIsAscii StepASCII
h  = do
                MutableBlock Word8 (PrimState prim)
-> Offset Word8 -> Char7 -> prim ()
forall (prim :: * -> *) container.
(PrimMonad prim, RandomAccess container prim Word8) =>
container -> Offset Word8 -> Char7 -> prim ()
UTF8.writeASCII MutableBlock Word8 (PrimState prim)
dst Offset Word8
dstIdx (Char7 -> Char7
opASCII (Char7 -> Char7) -> Char7 -> Char7
forall a b. (a -> b) -> a -> b
$ Word8 -> Char7
Char7 (Word8 -> Char7) -> Word8 -> Char7
forall a b. (a -> b) -> a -> b
$ StepASCII -> Word8
stepAsciiRawValue StepASCII
h)
                MutableBlock Word8 (PrimState prim)
-> CountOf Word8
-> CountOf Word8
-> Offset Word8
-> Offset Word8
-> prim (CountOf Word8)
loop MutableBlock Word8 (PrimState prim)
dst CountOf Word8
allocLen (CountOf Word8
nLen CountOf Word8 -> CountOf Word8 -> CountOf Word8
forall a. Additive a => a -> a -> a
+ CountOf Word8
1) (Offset Word8
dstIdxOffset Word8 -> Offset Word8 -> Offset Word8
forall a. Additive a => a -> a -> a
+Int -> Offset Word8
forall ty. Int -> Offset ty
Offset Int
1) (Offset Word8
srcIdxOffset Word8 -> Offset Word8 -> Offset Word8
forall a. Additive a => a -> a -> a
+Int -> Offset Word8
forall ty. Int -> Offset ty
Offset Int
1)
          | Bool
otherwise = do
              let !(CM Char
c1 Char
c2 Char
c3) = Char -> CM
op Char
c
                  !(Step Char
c Offset Word8
nextSrcIdx) = StepASCII -> container -> Offset Word8 -> Step
forall container.
Indexable container Word8 =>
StepASCII -> container -> Offset Word8 -> Step
UTF8.nextWith StepASCII
h container
src (Offset Word8
srcIdxOffset Word8 -> Offset Word8 -> Offset Word8
forall a. Additive a => a -> a -> a
+Int -> Offset Word8
forall ty. Int -> Offset ty
Offset Int
1)
              Offset Word8
nextDstIdx <- MutableBlock Word8 (PrimState prim)
-> Offset Word8 -> Char -> prim (Offset Word8)
forall (prim :: * -> *) container.
(PrimMonad prim, RandomAccess container prim Word8) =>
container -> Offset Word8 -> Char -> prim (Offset Word8)
UTF8.writeUTF8 MutableBlock Word8 (PrimState prim)
dst Offset Word8
dstIdx Char
c1
              if Char
c2 Char -> Char -> Bool
forall a. Eq a => a -> a -> Bool
== Char
'\0' -- We keep the most common case loop as short as possible.
                then MutableBlock Word8 (PrimState prim)
-> CountOf Word8
-> CountOf Word8
-> Offset Word8
-> Offset Word8
-> prim (CountOf Word8)
loop MutableBlock Word8 (PrimState prim)
dst CountOf Word8
allocLen (CountOf Word8
nLen CountOf Word8 -> CountOf Word8 -> CountOf Word8
forall a. Additive a => a -> a -> a
+ Int -> CountOf Word8
charToBytes (Char -> Int
forall a. Enum a => a -> Int
fromEnum Char
c1)) Offset Word8
nextDstIdx Offset Word8
nextSrcIdx
                else do
                  let !cSize :: CountOf Word8
cSize = Char -> CountOf Word8
eSize Char
c1 CountOf Word8 -> CountOf Word8 -> CountOf Word8
forall a. Additive a => a -> a -> a
+ Char -> CountOf Word8
eSize Char
c2 CountOf Word8 -> CountOf Word8 -> CountOf Word8
forall a. Additive a => a -> a -> a
+ Char -> CountOf Word8
eSize Char
c3
                  Offset Word8
nextDstIdx <- MutableBlock Word8 (PrimState prim)
-> Offset Word8 -> Char -> prim (Offset Word8)
forall (prim :: * -> *) container.
(PrimMonad prim, RandomAccess container prim Word8) =>
container -> Offset Word8 -> Char -> prim (Offset Word8)
UTF8.writeUTF8 MutableBlock Word8 (PrimState prim)
dst Offset Word8
nextDstIdx Char
c2
                  Offset Word8
nextDstIdx <- if Char
c3 Char -> Char -> Bool
forall a. Eq a => a -> a -> Bool
== Char
'\0' then Offset Word8 -> prim (Offset Word8)
forall (m :: * -> *) a. Monad m => a -> m a
return Offset Word8
nextDstIdx else MutableBlock Word8 (PrimState prim)
-> Offset Word8 -> Char -> prim (Offset Word8)
forall (prim :: * -> *) container.
(PrimMonad prim, RandomAccess container prim Word8) =>
container -> Offset Word8 -> Char -> prim (Offset Word8)
UTF8.writeUTF8 MutableBlock Word8 (PrimState prim)
dst Offset Word8
nextDstIdx Char
c3
                  MutableBlock Word8 (PrimState prim)
-> CountOf Word8
-> CountOf Word8
-> Offset Word8
-> Offset Word8
-> prim (CountOf Word8)
loop MutableBlock Word8 (PrimState prim)
dst CountOf Word8
allocLen (CountOf Word8
nLen CountOf Word8 -> CountOf Word8 -> CountOf Word8
forall a. Additive a => a -> a -> a
+ CountOf Word8
cSize) Offset Word8
nextDstIdx Offset Word8
nextSrcIdx
          where
            {-# NOINLINE realloc #-}
            realloc :: prim (CountOf Word8)
realloc = do
              let nAll :: CountOf Word8
nAll = CountOf Word8
allocLen CountOf Word8 -> CountOf Word8 -> CountOf Word8
forall a. Additive a => a -> a -> a
+ CountOf Word8
allocLen CountOf Word8 -> CountOf Word8 -> CountOf Word8
forall a. Additive a => a -> a -> a
+ CountOf Word8
1
              MutableBlock Word8 (PrimState prim)
nDst <- CountOf Word8 -> prim (MutableBlock Word8 (PrimState prim))
forall (prim :: * -> *) ty.
(PrimMonad prim, PrimType ty) =>
CountOf ty -> prim (MutableBlock ty (PrimState prim))
MBLK.new CountOf Word8
nAll
              MutableBlock Word8 (PrimState prim)
-> Offset Word8
-> MutableBlock Word8 (PrimState prim)
-> Offset Word8
-> CountOf Word8
-> prim ()
forall (prim :: * -> *) ty.
(PrimMonad prim, PrimType ty) =>
MutableBlock ty (PrimState prim)
-> Offset ty
-> MutableBlock ty (PrimState prim)
-> Offset ty
-> CountOf ty
-> prim ()
MBLK.unsafeCopyElements MutableBlock Word8 (PrimState prim)
nDst Offset Word8
0 MutableBlock Word8 (PrimState prim)
dst Offset Word8
0 CountOf Word8
nLen
              MutableBlock Word8 (PrimState prim)
-> CountOf Word8
-> CountOf Word8
-> Offset Word8
-> Offset Word8
-> prim (CountOf Word8)
loop MutableBlock Word8 (PrimState prim)
nDst CountOf Word8
nAll CountOf Word8
nLen Offset Word8
dstIdx Offset Word8
srcIdx
            h :: StepASCII
h = container -> Offset Word8 -> StepASCII
forall container.
Indexable container Word8 =>
container -> Offset Word8 -> StepASCII
UTF8.nextAscii container
src Offset Word8
srcIdx

-- | Convert a 'String' to the upper-case equivalent.
upper :: String -> String
upper :: String -> String
upper = (Char7 -> Char7) -> (Char -> CM) -> String -> String
caseConvert Char7 -> Char7
c7Upper Char -> CM
upperMapping

-- | Convert a 'String' to the upper-case equivalent.
lower :: String -> String
lower :: String -> String
lower = (Char7 -> Char7) -> (Char -> CM) -> String -> String
caseConvert Char7 -> Char7
c7Lower Char -> CM
lowerMapping

-- | Convert a 'String' to the unicode case fold equivalent.
--
-- Case folding is mostly used for caseless comparison of strings.
caseFold :: String -> String
caseFold :: String -> String
caseFold = (Char7 -> Char7) -> (Char -> CM) -> String -> String
caseConvert Char7 -> Char7
c7Upper Char -> CM
foldMapping

-- | Check whether the first string is a prefix of the second string.
isPrefixOf :: String -> String -> Bool
isPrefixOf :: String -> String -> Bool
isPrefixOf (String UArray Word8
needle) (String UArray Word8
haystack) = UArray Word8 -> UArray Word8 -> Bool
forall ty. PrimType ty => UArray ty -> UArray ty -> Bool
C.isPrefixOf UArray Word8
needle UArray Word8
haystack

-- | Check whether the first string is a suffix of the second string.
isSuffixOf :: String -> String -> Bool
isSuffixOf :: String -> String -> Bool
isSuffixOf (String UArray Word8
needle) (String UArray Word8
haystack)
    | CountOf Word8
needleLen CountOf Word8 -> CountOf Word8 -> Bool
forall a. Ord a => a -> a -> Bool
> CountOf Word8
hayLen = Bool
False
    | Bool
otherwise          = UArray Word8
needle UArray Word8 -> UArray Word8 -> Bool
forall a. Eq a => a -> a -> Bool
== CountOf Word8 -> UArray Word8 -> UArray Word8
forall ty. CountOf ty -> UArray ty -> UArray ty
C.revTake CountOf Word8
needleLen UArray Word8
haystack
  where
    needleLen :: CountOf Word8
needleLen = UArray Word8 -> CountOf Word8
forall ty. UArray ty -> CountOf ty
C.length UArray Word8
needle
    hayLen :: CountOf Word8
hayLen    = UArray Word8 -> CountOf Word8
forall ty. UArray ty -> CountOf ty
C.length UArray Word8
haystack

-- | Check whether the first string is contains within the second string.
--
-- TODO: implemented the naive way and thus terribly inefficient, reimplement properly
isInfixOf :: String -> String -> Bool
isInfixOf :: String -> String -> Bool
isInfixOf (String UArray Word8
needle) (String UArray Word8
haystack)
    = Maybe (CountOf Word8) -> UArray Word8 -> Bool
loop (CountOf Word8
hayLen CountOf Word8 -> CountOf Word8 -> Difference (CountOf Word8)
forall a. Subtractive a => a -> a -> Difference a
- CountOf Word8
needleLen) UArray Word8
haystack
    where
      needleLen :: CountOf Word8
needleLen = UArray Word8 -> CountOf Word8
forall ty. UArray ty -> CountOf ty
C.length UArray Word8
needle
      hayLen :: CountOf Word8
hayLen    = UArray Word8 -> CountOf Word8
forall ty. UArray ty -> CountOf ty
C.length UArray Word8
haystack
      loop :: Maybe (CountOf Word8) -> UArray Word8 -> Bool
loop Maybe (CountOf Word8)
Nothing    UArray Word8
_         = Bool
False
      loop (Just CountOf Word8
cnt) UArray Word8
haystack' = UArray Word8
needle UArray Word8 -> UArray Word8 -> Bool
forall a. Eq a => a -> a -> Bool
== CountOf Word8 -> UArray Word8 -> UArray Word8
forall ty. CountOf ty -> UArray ty -> UArray ty
C.take CountOf Word8
needleLen UArray Word8
haystack' Bool -> Bool -> Bool
|| Maybe (CountOf Word8) -> UArray Word8 -> Bool
loop (CountOf Word8
cntCountOf Word8 -> CountOf Word8 -> Difference (CountOf Word8)
forall a. Subtractive a => a -> a -> Difference a
-CountOf Word8
1) (CountOf Word8 -> UArray Word8 -> UArray Word8
forall ty. CountOf ty -> UArray ty -> UArray ty
C.drop CountOf Word8
1 UArray Word8
haystack')

-- | Try to strip a prefix from the start of a String.
--
-- If the prefix is not starting the string, then Nothing is returned,
-- otherwise the striped string is returned
stripPrefix :: String -> String -> Maybe String
stripPrefix :: String -> String -> Maybe String
stripPrefix (String UArray Word8
suffix) (String UArray Word8
arr)
    | UArray Word8 -> UArray Word8 -> Bool
forall ty. PrimType ty => UArray ty -> UArray ty -> Bool
C.isPrefixOf UArray Word8
suffix UArray Word8
arr = String -> Maybe String
forall a. a -> Maybe a
Just (String -> Maybe String) -> String -> Maybe String
forall a b. (a -> b) -> a -> b
$ UArray Word8 -> String
String (UArray Word8 -> String) -> UArray Word8 -> String
forall a b. (a -> b) -> a -> b
$ CountOf Word8 -> UArray Word8 -> UArray Word8
forall ty. CountOf ty -> UArray ty -> UArray ty
C.drop (UArray Word8 -> CountOf Word8
forall ty. UArray ty -> CountOf ty
C.length UArray Word8
suffix) UArray Word8
arr
    | Bool
otherwise               = Maybe String
forall a. Maybe a
Nothing

-- | Try to strip a suffix from the end of a String.
--
-- If the suffix is not ending the string, then Nothing is returned,
-- otherwise the striped string is returned
stripSuffix :: String -> String -> Maybe String
stripSuffix :: String -> String -> Maybe String
stripSuffix (String UArray Word8
prefix) (String UArray Word8
arr)
    | UArray Word8 -> UArray Word8 -> Bool
forall ty. PrimType ty => UArray ty -> UArray ty -> Bool
C.isSuffixOf UArray Word8
prefix UArray Word8
arr = String -> Maybe String
forall a. a -> Maybe a
Just (String -> Maybe String) -> String -> Maybe String
forall a b. (a -> b) -> a -> b
$ UArray Word8 -> String
String (UArray Word8 -> String) -> UArray Word8 -> String
forall a b. (a -> b) -> a -> b
$ CountOf Word8 -> UArray Word8 -> UArray Word8
forall ty. CountOf ty -> UArray ty -> UArray ty
C.revDrop (UArray Word8 -> CountOf Word8
forall ty. UArray ty -> CountOf ty
C.length UArray Word8
prefix) UArray Word8
arr
    | Bool
otherwise               = Maybe String
forall a. Maybe a
Nothing

all :: (Char -> Bool) -> String -> Bool
all :: (Char -> Bool) -> String -> Bool
all Char -> Bool
predicate (String UArray Word8
arr) = (Block Word8 -> Bool)
-> (FinalPtr Word8 -> Ptr Word8 -> ST Any Bool)
-> UArray Word8
-> Bool
forall ty a s.
(Block ty -> a)
-> (FinalPtr ty -> Ptr ty -> ST s a) -> UArray ty -> a
C.onBackend Block Word8 -> Bool
goBA (\FinalPtr Word8
_ -> Bool -> ST Any Bool
forall (f :: * -> *) a. Applicative f => a -> f a
pure (Bool -> ST Any Bool)
-> (Ptr Word8 -> Bool) -> Ptr Word8 -> ST Any Bool
forall k (cat :: k -> k -> *) (b :: k) (c :: k) (a :: k).
Category cat =>
cat b c -> cat a b -> cat a c
. Ptr Word8 -> Bool
goAddr) UArray Word8
arr
  where
    !(C.ValidRange Offset Word8
start Offset Word8
end) = UArray Word8 -> ValidRange Word8
forall ty. UArray ty -> ValidRange ty
C.offsetsValidRange UArray Word8
arr
    goBA :: Block Word8 -> Bool
goBA Block Word8
ba   = (Char -> Bool)
-> Block Word8 -> Offset Word8 -> Offset Word8 -> Bool
forall container.
Indexable container Word8 =>
(Char -> Bool) -> container -> Offset Word8 -> Offset Word8 -> Bool
UTF8.all Char -> Bool
predicate Block Word8
ba Offset Word8
start Offset Word8
end
    goAddr :: Ptr Word8 -> Bool
goAddr Ptr Word8
addr = (Char -> Bool) -> Ptr Word8 -> Offset Word8 -> Offset Word8 -> Bool
forall container.
Indexable container Word8 =>
(Char -> Bool) -> container -> Offset Word8 -> Offset Word8 -> Bool
UTF8.all Char -> Bool
predicate Ptr Word8
addr Offset Word8
start Offset Word8
end

any :: (Char -> Bool) -> String -> Bool
any :: (Char -> Bool) -> String -> Bool
any Char -> Bool
predicate (String UArray Word8
arr) = (Block Word8 -> Bool)
-> (FinalPtr Word8 -> Ptr Word8 -> ST Any Bool)
-> UArray Word8
-> Bool
forall ty a s.
(Block ty -> a)
-> (FinalPtr ty -> Ptr ty -> ST s a) -> UArray ty -> a
C.onBackend Block Word8 -> Bool
goBA (\FinalPtr Word8
_ -> Bool -> ST Any Bool
forall (f :: * -> *) a. Applicative f => a -> f a
pure (Bool -> ST Any Bool)
-> (Ptr Word8 -> Bool) -> Ptr Word8 -> ST Any Bool
forall k (cat :: k -> k -> *) (b :: k) (c :: k) (a :: k).
Category cat =>
cat b c -> cat a b -> cat a c
. Ptr Word8 -> Bool
goAddr) UArray Word8
arr
  where
    !(C.ValidRange Offset Word8
start Offset Word8
end) = UArray Word8 -> ValidRange Word8
forall ty. UArray ty -> ValidRange ty
C.offsetsValidRange UArray Word8
arr
    goBA :: Block Word8 -> Bool
goBA Block Word8
ba   = (Char -> Bool)
-> Block Word8 -> Offset Word8 -> Offset Word8 -> Bool
forall container.
Indexable container Word8 =>
(Char -> Bool) -> container -> Offset Word8 -> Offset Word8 -> Bool
UTF8.any Char -> Bool
predicate Block Word8
ba Offset Word8
start Offset Word8
end
    goAddr :: Ptr Word8 -> Bool
goAddr Ptr Word8
addr = (Char -> Bool) -> Ptr Word8 -> Offset Word8 -> Offset Word8 -> Bool
forall container.
Indexable container Word8 =>
(Char -> Bool) -> container -> Offset Word8 -> Offset Word8 -> Bool
UTF8.any Char -> Bool
predicate Ptr Word8
addr Offset Word8
start Offset Word8
end

-- | Transform string @src@ to base64 binary representation.
toBase64 :: String -> String
toBase64 :: String -> String
toBase64 (String UArray Word8
src) = UArray Word8 -> String
fromBytesUnsafe (UArray Word8 -> String)
-> (Bool -> UArray Word8) -> Bool -> String
forall k (cat :: k -> k -> *) (b :: k) (c :: k) (a :: k).
Category cat =>
cat b c -> cat a b -> cat a c
. Addr# -> UArray Word8 -> Bool -> UArray Word8
forall ty.
PrimType ty =>
Addr# -> UArray ty -> Bool -> UArray Word8
Vec.toBase64Internal Addr#
set UArray Word8
src (Bool -> String) -> Bool -> String
forall a b. (a -> b) -> a -> b
$ Bool
True
  where
    !set :: Addr#
set = Addr#
"ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789+/"#

-- | Transform string @src@ to URL-safe base64 binary representation.
-- The result will be either padded or unpadded, depending on the boolean
-- @padded@ argument.
toBase64URL :: Bool -> String -> String
toBase64URL :: Bool -> String -> String
toBase64URL Bool
padded (String UArray Word8
src) = UArray Word8 -> String
fromBytesUnsafe (UArray Word8 -> String)
-> (Bool -> UArray Word8) -> Bool -> String
forall k (cat :: k -> k -> *) (b :: k) (c :: k) (a :: k).
Category cat =>
cat b c -> cat a b -> cat a c
. Addr# -> UArray Word8 -> Bool -> UArray Word8
forall ty.
PrimType ty =>
Addr# -> UArray ty -> Bool -> UArray Word8
Vec.toBase64Internal Addr#
set UArray Word8
src (Bool -> String) -> Bool -> String
forall a b. (a -> b) -> a -> b
$ Bool
padded
  where
    !set :: Addr#
set = Addr#
"ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789-_"#

-- | Transform string @src@ to OpenBSD base64 binary representation.
toBase64OpenBSD :: String -> String
toBase64OpenBSD :: String -> String
toBase64OpenBSD (String UArray Word8
src) = UArray Word8 -> String
fromBytesUnsafe (UArray Word8 -> String)
-> (Bool -> UArray Word8) -> Bool -> String
forall k (cat :: k -> k -> *) (b :: k) (c :: k) (a :: k).
Category cat =>
cat b c -> cat a b -> cat a c
. Addr# -> UArray Word8 -> Bool -> UArray Word8
forall ty.
PrimType ty =>
Addr# -> UArray ty -> Bool -> UArray Word8
Vec.toBase64Internal Addr#
set UArray Word8
src (Bool -> String) -> Bool -> String
forall a b. (a -> b) -> a -> b
$ Bool
False
  where
    !set :: Addr#
set = Addr#
"./ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789"#