{-# LANGUAGE CPP #-}
{-# LANGUAGE BangPatterns #-}
{-# LANGUAGE DeriveDataTypeable #-}
{-# LANGUAGE TypeFamilies #-}
#if __GLASGOW_HASKELL__ >= 703
{-# LANGUAGE Unsafe #-}
#endif
{-# OPTIONS_HADDOCK not-home #-}
module Data.ByteString.Lazy.Internal (
ByteString(..),
chunk,
foldrChunks,
foldlChunks,
invariant,
checkInvariant,
defaultChunkSize,
smallChunkSize,
chunkOverhead,
packBytes, packChars,
unpackBytes, unpackChars,
fromStrict, toStrict,
) where
import Prelude hiding (concat)
import qualified Data.ByteString.Internal as S
import Data.Word (Word8)
import Foreign.ForeignPtr (withForeignPtr)
import Foreign.Ptr (plusPtr)
import Foreign.Storable (Storable(sizeOf))
#if MIN_VERSION_base(4,13,0)
import Data.Semigroup (Semigroup (sconcat, stimes))
import Data.List.NonEmpty (NonEmpty ((:|)))
#elif MIN_VERSION_base(4,9,0)
import Data.Semigroup (Semigroup ((<>), sconcat, stimes))
import Data.List.NonEmpty (NonEmpty ((:|)))
#endif
#if !(MIN_VERSION_base(4,8,0))
import Data.Monoid (Monoid(..))
#endif
import Control.DeepSeq (NFData, rnf)
import Data.String (IsString(..))
import Data.Typeable (Typeable)
import Data.Data (Data(..), mkNoRepType)
#if MIN_VERSION_base(4,7,0)
import GHC.Exts (IsList(..))
#endif
data ByteString = Empty | Chunk {-# UNPACK #-} !S.ByteString ByteString
deriving (Typeable)
instance Eq ByteString where
== :: ByteString -> ByteString -> Bool
(==) = ByteString -> ByteString -> Bool
eq
instance Ord ByteString where
compare :: ByteString -> ByteString -> Ordering
compare = ByteString -> ByteString -> Ordering
cmp
#if MIN_VERSION_base(4,9,0)
instance Semigroup ByteString where
<> :: ByteString -> ByteString -> ByteString
(<>) = ByteString -> ByteString -> ByteString
append
sconcat :: NonEmpty ByteString -> ByteString
sconcat (ByteString
b:|[ByteString]
bs) = [ByteString] -> ByteString
concat (ByteString
bByteString -> [ByteString] -> [ByteString]
forall a. a -> [a] -> [a]
:[ByteString]
bs)
stimes :: forall b. Integral b => b -> ByteString -> ByteString
stimes = b -> ByteString -> ByteString
forall b. Integral b => b -> ByteString -> ByteString
times
#endif
instance Monoid ByteString where
mempty :: ByteString
mempty = ByteString
Empty
#if MIN_VERSION_base(4,9,0)
mappend :: ByteString -> ByteString -> ByteString
mappend = ByteString -> ByteString -> ByteString
forall a. Semigroup a => a -> a -> a
(<>)
#else
mappend = append
#endif
mconcat :: [ByteString] -> ByteString
mconcat = [ByteString] -> ByteString
concat
instance NFData ByteString where
rnf :: ByteString -> ()
rnf ByteString
Empty = ()
rnf (Chunk ByteString
_ ByteString
b) = ByteString -> ()
forall a. NFData a => a -> ()
rnf ByteString
b
instance Show ByteString where
showsPrec :: Int -> ByteString -> ShowS
showsPrec Int
p ByteString
ps String
r = Int -> String -> ShowS
forall a. Show a => Int -> a -> ShowS
showsPrec Int
p (ByteString -> String
unpackChars ByteString
ps) String
r
instance Read ByteString where
readsPrec :: Int -> ReadS ByteString
readsPrec Int
p String
str = [ (String -> ByteString
packChars String
x, String
y) | (String
x, String
y) <- Int -> ReadS String
forall a. Read a => Int -> ReadS a
readsPrec Int
p String
str ]
#if MIN_VERSION_base(4,7,0)
instance IsList ByteString where
type Item ByteString = Word8
fromList :: [Item ByteString] -> ByteString
fromList = [Word8] -> ByteString
[Item ByteString] -> ByteString
packBytes
toList :: ByteString -> [Item ByteString]
toList = ByteString -> [Word8]
ByteString -> [Item ByteString]
unpackBytes
#endif
instance IsString ByteString where
fromString :: String -> ByteString
fromString = String -> ByteString
packChars
instance Data ByteString where
gfoldl :: forall (c :: * -> *).
(forall d b. Data d => c (d -> b) -> d -> c b)
-> (forall g. g -> c g) -> ByteString -> c ByteString
gfoldl forall d b. Data d => c (d -> b) -> d -> c b
f forall g. g -> c g
z ByteString
txt = ([Word8] -> ByteString) -> c ([Word8] -> ByteString)
forall g. g -> c g
z [Word8] -> ByteString
packBytes c ([Word8] -> ByteString) -> [Word8] -> c ByteString
forall d b. Data d => c (d -> b) -> d -> c b
`f` ByteString -> [Word8]
unpackBytes ByteString
txt
toConstr :: ByteString -> Constr
toConstr ByteString
_ = String -> Constr
forall a. HasCallStack => String -> a
error String
"Data.ByteString.Lazy.ByteString.toConstr"
gunfold :: forall (c :: * -> *).
(forall b r. Data b => c (b -> r) -> c r)
-> (forall r. r -> c r) -> Constr -> c ByteString
gunfold forall b r. Data b => c (b -> r) -> c r
_ forall r. r -> c r
_ = String -> Constr -> c ByteString
forall a. HasCallStack => String -> a
error String
"Data.ByteString.Lazy.ByteString.gunfold"
dataTypeOf :: ByteString -> DataType
dataTypeOf ByteString
_ = String -> DataType
mkNoRepType String
"Data.ByteString.Lazy.ByteString"
packBytes :: [Word8] -> ByteString
packBytes :: [Word8] -> ByteString
packBytes [] = ByteString
Empty
packBytes [Word8]
cs0 =
Int -> [Word8] -> ByteString
packChunks Int
32 [Word8]
cs0
where
packChunks :: Int -> [Word8] -> ByteString
packChunks Int
n [Word8]
cs = case Int -> [Word8] -> (ByteString, [Word8])
S.packUptoLenBytes Int
n [Word8]
cs of
(ByteString
bs, []) -> ByteString -> ByteString -> ByteString
chunk ByteString
bs ByteString
Empty
(ByteString
bs, [Word8]
cs') -> ByteString -> ByteString -> ByteString
Chunk ByteString
bs (Int -> [Word8] -> ByteString
packChunks (Int -> Int -> Int
forall a. Ord a => a -> a -> a
min (Int
n Int -> Int -> Int
forall a. Num a => a -> a -> a
* Int
2) Int
smallChunkSize) [Word8]
cs')
packChars :: [Char] -> ByteString
packChars :: String -> ByteString
packChars [] = ByteString
Empty
packChars String
cs0 = Int -> String -> ByteString
packChunks Int
32 String
cs0
where
packChunks :: Int -> String -> ByteString
packChunks Int
n String
cs = case Int -> String -> (ByteString, String)
S.packUptoLenChars Int
n String
cs of
(ByteString
bs, []) -> ByteString -> ByteString -> ByteString
chunk ByteString
bs ByteString
Empty
(ByteString
bs, String
cs') -> ByteString -> ByteString -> ByteString
Chunk ByteString
bs (Int -> String -> ByteString
packChunks (Int -> Int -> Int
forall a. Ord a => a -> a -> a
min (Int
n Int -> Int -> Int
forall a. Num a => a -> a -> a
* Int
2) Int
smallChunkSize) String
cs')
unpackBytes :: ByteString -> [Word8]
unpackBytes :: ByteString -> [Word8]
unpackBytes ByteString
Empty = []
unpackBytes (Chunk ByteString
c ByteString
cs) = ByteString -> [Word8] -> [Word8]
S.unpackAppendBytesLazy ByteString
c (ByteString -> [Word8]
unpackBytes ByteString
cs)
unpackChars :: ByteString -> [Char]
unpackChars :: ByteString -> String
unpackChars ByteString
Empty = []
unpackChars (Chunk ByteString
c ByteString
cs) = ByteString -> ShowS
S.unpackAppendCharsLazy ByteString
c (ByteString -> String
unpackChars ByteString
cs)
invariant :: ByteString -> Bool
invariant :: ByteString -> Bool
invariant ByteString
Empty = Bool
True
invariant (Chunk (S.BS ForeignPtr Word8
_ Int
len) ByteString
cs) = Int
len Int -> Int -> Bool
forall a. Ord a => a -> a -> Bool
> Int
0 Bool -> Bool -> Bool
&& ByteString -> Bool
invariant ByteString
cs
checkInvariant :: ByteString -> ByteString
checkInvariant :: ByteString -> ByteString
checkInvariant ByteString
Empty = ByteString
Empty
checkInvariant (Chunk c :: ByteString
c@(S.BS ForeignPtr Word8
_ Int
len) ByteString
cs)
| Int
len Int -> Int -> Bool
forall a. Ord a => a -> a -> Bool
> Int
0 = ByteString -> ByteString -> ByteString
Chunk ByteString
c (ByteString -> ByteString
checkInvariant ByteString
cs)
| Bool
otherwise = String -> ByteString
forall a. HasCallStack => String -> a
error (String -> ByteString) -> String -> ByteString
forall a b. (a -> b) -> a -> b
$ String
"Data.ByteString.Lazy: invariant violation:"
String -> ShowS
forall a. [a] -> [a] -> [a]
++ ByteString -> String
forall a. Show a => a -> String
show (ByteString -> ByteString -> ByteString
Chunk ByteString
c ByteString
cs)
chunk :: S.ByteString -> ByteString -> ByteString
chunk :: ByteString -> ByteString -> ByteString
chunk c :: ByteString
c@(S.BS ForeignPtr Word8
_ Int
len) ByteString
cs | Int
len Int -> Int -> Bool
forall a. Eq a => a -> a -> Bool
== Int
0 = ByteString
cs
| Bool
otherwise = ByteString -> ByteString -> ByteString
Chunk ByteString
c ByteString
cs
{-# INLINE chunk #-}
foldrChunks :: (S.ByteString -> a -> a) -> a -> ByteString -> a
foldrChunks :: forall a. (ByteString -> a -> a) -> a -> ByteString -> a
foldrChunks ByteString -> a -> a
f a
z = ByteString -> a
go
where go :: ByteString -> a
go ByteString
Empty = a
z
go (Chunk ByteString
c ByteString
cs) = ByteString -> a -> a
f ByteString
c (ByteString -> a
go ByteString
cs)
{-# INLINE foldrChunks #-}
foldlChunks :: (a -> S.ByteString -> a) -> a -> ByteString -> a
foldlChunks :: forall a. (a -> ByteString -> a) -> a -> ByteString -> a
foldlChunks a -> ByteString -> a
f = a -> ByteString -> a
go
where go :: a -> ByteString -> a
go !a
a ByteString
Empty = a
a
go !a
a (Chunk ByteString
c ByteString
cs) = a -> ByteString -> a
go (a -> ByteString -> a
f a
a ByteString
c) ByteString
cs
{-# INLINE foldlChunks #-}
defaultChunkSize :: Int
defaultChunkSize :: Int
defaultChunkSize = Int
32 Int -> Int -> Int
forall a. Num a => a -> a -> a
* Int
k Int -> Int -> Int
forall a. Num a => a -> a -> a
- Int
chunkOverhead
where k :: Int
k = Int
1024
smallChunkSize :: Int
smallChunkSize :: Int
smallChunkSize = Int
4 Int -> Int -> Int
forall a. Num a => a -> a -> a
* Int
k Int -> Int -> Int
forall a. Num a => a -> a -> a
- Int
chunkOverhead
where k :: Int
k = Int
1024
chunkOverhead :: Int
chunkOverhead :: Int
chunkOverhead = Int
2 Int -> Int -> Int
forall a. Num a => a -> a -> a
* Int -> Int
forall a. Storable a => a -> Int
sizeOf (Int
forall a. HasCallStack => a
undefined :: Int)
eq :: ByteString -> ByteString -> Bool
eq :: ByteString -> ByteString -> Bool
eq ByteString
Empty ByteString
Empty = Bool
True
eq ByteString
Empty ByteString
_ = Bool
False
eq ByteString
_ ByteString
Empty = Bool
False
eq (Chunk a :: ByteString
a@(S.BS ForeignPtr Word8
ap Int
al) ByteString
as) (Chunk b :: ByteString
b@(S.BS ForeignPtr Word8
bp Int
bl) ByteString
bs) =
case Int -> Int -> Ordering
forall a. Ord a => a -> a -> Ordering
compare Int
al Int
bl of
Ordering
LT -> ByteString
a ByteString -> ByteString -> Bool
forall a. Eq a => a -> a -> Bool
== ForeignPtr Word8 -> Int -> ByteString
S.BS ForeignPtr Word8
bp Int
al Bool -> Bool -> Bool
&& ByteString -> ByteString -> Bool
eq ByteString
as (ByteString -> ByteString -> ByteString
Chunk (ForeignPtr Word8 -> Int -> ByteString
S.BS (ForeignPtr Word8 -> Int -> ForeignPtr Word8
forall a b. ForeignPtr a -> Int -> ForeignPtr b
S.plusForeignPtr ForeignPtr Word8
bp Int
al) (Int
bl Int -> Int -> Int
forall a. Num a => a -> a -> a
- Int
al)) ByteString
bs)
Ordering
EQ -> ByteString
a ByteString -> ByteString -> Bool
forall a. Eq a => a -> a -> Bool
== ByteString
b Bool -> Bool -> Bool
&& ByteString -> ByteString -> Bool
eq ByteString
as ByteString
bs
Ordering
GT -> ForeignPtr Word8 -> Int -> ByteString
S.BS ForeignPtr Word8
ap Int
bl ByteString -> ByteString -> Bool
forall a. Eq a => a -> a -> Bool
== ByteString
b Bool -> Bool -> Bool
&& ByteString -> ByteString -> Bool
eq (ByteString -> ByteString -> ByteString
Chunk (ForeignPtr Word8 -> Int -> ByteString
S.BS (ForeignPtr Word8 -> Int -> ForeignPtr Word8
forall a b. ForeignPtr a -> Int -> ForeignPtr b
S.plusForeignPtr ForeignPtr Word8
ap Int
bl) (Int
al Int -> Int -> Int
forall a. Num a => a -> a -> a
- Int
bl)) ByteString
as) ByteString
bs
cmp :: ByteString -> ByteString -> Ordering
cmp :: ByteString -> ByteString -> Ordering
cmp ByteString
Empty ByteString
Empty = Ordering
EQ
cmp ByteString
Empty ByteString
_ = Ordering
LT
cmp ByteString
_ ByteString
Empty = Ordering
GT
cmp (Chunk a :: ByteString
a@(S.BS ForeignPtr Word8
ap Int
al) ByteString
as) (Chunk b :: ByteString
b@(S.BS ForeignPtr Word8
bp Int
bl) ByteString
bs) =
case Int -> Int -> Ordering
forall a. Ord a => a -> a -> Ordering
compare Int
al Int
bl of
Ordering
LT -> case ByteString -> ByteString -> Ordering
forall a. Ord a => a -> a -> Ordering
compare ByteString
a (ForeignPtr Word8 -> Int -> ByteString
S.BS ForeignPtr Word8
bp Int
al) of
Ordering
EQ -> ByteString -> ByteString -> Ordering
cmp ByteString
as (ByteString -> ByteString -> ByteString
Chunk (ForeignPtr Word8 -> Int -> ByteString
S.BS (ForeignPtr Word8 -> Int -> ForeignPtr Word8
forall a b. ForeignPtr a -> Int -> ForeignPtr b
S.plusForeignPtr ForeignPtr Word8
bp Int
al) (Int
bl Int -> Int -> Int
forall a. Num a => a -> a -> a
- Int
al)) ByteString
bs)
Ordering
result -> Ordering
result
Ordering
EQ -> case ByteString -> ByteString -> Ordering
forall a. Ord a => a -> a -> Ordering
compare ByteString
a ByteString
b of
Ordering
EQ -> ByteString -> ByteString -> Ordering
cmp ByteString
as ByteString
bs
Ordering
result -> Ordering
result
Ordering
GT -> case ByteString -> ByteString -> Ordering
forall a. Ord a => a -> a -> Ordering
compare (ForeignPtr Word8 -> Int -> ByteString
S.BS ForeignPtr Word8
ap Int
bl) ByteString
b of
Ordering
EQ -> ByteString -> ByteString -> Ordering
cmp (ByteString -> ByteString -> ByteString
Chunk (ForeignPtr Word8 -> Int -> ByteString
S.BS (ForeignPtr Word8 -> Int -> ForeignPtr Word8
forall a b. ForeignPtr a -> Int -> ForeignPtr b
S.plusForeignPtr ForeignPtr Word8
ap Int
bl) (Int
al Int -> Int -> Int
forall a. Num a => a -> a -> a
- Int
bl)) ByteString
as) ByteString
bs
Ordering
result -> Ordering
result
append :: ByteString -> ByteString -> ByteString
append :: ByteString -> ByteString -> ByteString
append ByteString
xs ByteString
ys = (ByteString -> ByteString -> ByteString)
-> ByteString -> ByteString -> ByteString
forall a. (ByteString -> a -> a) -> a -> ByteString -> a
foldrChunks ByteString -> ByteString -> ByteString
Chunk ByteString
ys ByteString
xs
concat :: [ByteString] -> ByteString
concat :: [ByteString] -> ByteString
concat = [ByteString] -> ByteString
to
where
go :: ByteString -> [ByteString] -> ByteString
go ByteString
Empty [ByteString]
css = [ByteString] -> ByteString
to [ByteString]
css
go (Chunk ByteString
c ByteString
cs) [ByteString]
css = ByteString -> ByteString -> ByteString
Chunk ByteString
c (ByteString -> [ByteString] -> ByteString
go ByteString
cs [ByteString]
css)
to :: [ByteString] -> ByteString
to [] = ByteString
Empty
to (ByteString
cs:[ByteString]
css) = ByteString -> [ByteString] -> ByteString
go ByteString
cs [ByteString]
css
#if MIN_VERSION_base(4,9,0)
times :: Integral a => a -> ByteString -> ByteString
times :: forall b. Integral b => b -> ByteString -> ByteString
times a
0 ByteString
_ = ByteString
Empty
times a
n ByteString
lbs0
| a
n a -> a -> Bool
forall a. Ord a => a -> a -> Bool
< a
0 = String -> ByteString
forall a. HasCallStack => String -> a
error String
"stimes: non-negative multiplier expected"
| Bool
otherwise = case ByteString
lbs0 of
ByteString
Empty -> ByteString
Empty
Chunk ByteString
bs ByteString
lbs -> ByteString -> ByteString -> ByteString
Chunk ByteString
bs (ByteString -> ByteString
go ByteString
lbs)
where
go :: ByteString -> ByteString
go ByteString
Empty = a -> ByteString -> ByteString
forall b. Integral b => b -> ByteString -> ByteString
times (a
na -> a -> a
forall a. Num a => a -> a -> a
-a
1) ByteString
lbs0
go (Chunk ByteString
c ByteString
cs) = ByteString -> ByteString -> ByteString
Chunk ByteString
c (ByteString -> ByteString
go ByteString
cs)
#endif
fromStrict :: S.ByteString -> ByteString
fromStrict :: ByteString -> ByteString
fromStrict (S.BS ForeignPtr Word8
_ Int
0) = ByteString
Empty
fromStrict ByteString
bs = ByteString -> ByteString -> ByteString
Chunk ByteString
bs ByteString
Empty
toStrict :: ByteString -> S.ByteString
toStrict :: ByteString -> ByteString
toStrict = \ByteString
cs -> ByteString -> ByteString -> ByteString
goLen0 ByteString
cs ByteString
cs
where
goLen0 :: ByteString -> ByteString -> ByteString
goLen0 ByteString
_ ByteString
Empty = ForeignPtr Word8 -> Int -> ByteString
S.BS ForeignPtr Word8
S.nullForeignPtr Int
0
goLen0 ByteString
cs0 (Chunk (S.BS ForeignPtr Word8
_ Int
0) ByteString
cs) = ByteString -> ByteString -> ByteString
goLen0 ByteString
cs0 ByteString
cs
goLen0 ByteString
cs0 (Chunk ByteString
c ByteString
cs) = ByteString -> ByteString -> ByteString -> ByteString
goLen1 ByteString
cs0 ByteString
c ByteString
cs
goLen1 :: ByteString -> ByteString -> ByteString -> ByteString
goLen1 ByteString
_ ByteString
bs ByteString
Empty = ByteString
bs
goLen1 ByteString
cs0 ByteString
bs (Chunk (S.BS ForeignPtr Word8
_ Int
0) ByteString
cs) = ByteString -> ByteString -> ByteString -> ByteString
goLen1 ByteString
cs0 ByteString
bs ByteString
cs
goLen1 ByteString
cs0 (S.BS ForeignPtr Word8
_ Int
bl) (Chunk (S.BS ForeignPtr Word8
_ Int
cl) ByteString
cs) =
ByteString -> Int -> ByteString -> ByteString
goLen ByteString
cs0 (String -> Int -> Int -> Int
S.checkedAdd String
"Lazy.concat" Int
bl Int
cl) ByteString
cs
goLen :: ByteString -> Int -> ByteString -> ByteString
goLen ByteString
cs0 !Int
total (Chunk (S.BS ForeignPtr Word8
_ Int
cl) ByteString
cs) =
ByteString -> Int -> ByteString -> ByteString
goLen ByteString
cs0 (String -> Int -> Int -> Int
S.checkedAdd String
"Lazy.concat" Int
total Int
cl) ByteString
cs
goLen ByteString
cs0 Int
total ByteString
Empty =
Int -> (Ptr Word8 -> IO ()) -> ByteString
S.unsafeCreate Int
total ((Ptr Word8 -> IO ()) -> ByteString)
-> (Ptr Word8 -> IO ()) -> ByteString
forall a b. (a -> b) -> a -> b
$ \Ptr Word8
ptr -> ByteString -> Ptr Word8 -> IO ()
goCopy ByteString
cs0 Ptr Word8
ptr
goCopy :: ByteString -> Ptr Word8 -> IO ()
goCopy ByteString
Empty !Ptr Word8
_ = () -> IO ()
forall (m :: * -> *) a. Monad m => a -> m a
return ()
goCopy (Chunk (S.BS ForeignPtr Word8
_ Int
0 ) ByteString
cs) !Ptr Word8
ptr = ByteString -> Ptr Word8 -> IO ()
goCopy ByteString
cs Ptr Word8
ptr
goCopy (Chunk (S.BS ForeignPtr Word8
fp Int
len) ByteString
cs) !Ptr Word8
ptr =
ForeignPtr Word8 -> (Ptr Word8 -> IO ()) -> IO ()
forall a b. ForeignPtr a -> (Ptr a -> IO b) -> IO b
withForeignPtr ForeignPtr Word8
fp ((Ptr Word8 -> IO ()) -> IO ()) -> (Ptr Word8 -> IO ()) -> IO ()
forall a b. (a -> b) -> a -> b
$ \Ptr Word8
p -> do
Ptr Word8 -> Ptr Word8 -> Int -> IO ()
S.memcpy Ptr Word8
ptr Ptr Word8
p Int
len
ByteString -> Ptr Word8 -> IO ()
goCopy ByteString
cs (Ptr Word8
ptr Ptr Word8 -> Int -> Ptr Word8
forall a b. Ptr a -> Int -> Ptr b
`plusPtr` Int
len)