-- |
-- Module      : Data.ByteArray.Methods
-- License     : BSD-style
-- Maintainer  : Vincent Hanquez <vincent@snarc.org>
-- Stability   : stable
-- Portability : Good
--
{-# LANGUAGE CPP #-}
{-# LANGUAGE BangPatterns #-}
module Data.ByteArray.Methods
    ( alloc
    , allocAndFreeze
    , create
    , unsafeCreate
    , pack
    , unpack
    , uncons
    , empty
    , singleton
    , cons
    , snoc
    , null
    , replicate
    , zero
    , copy
    , take
    , drop
    , span
    , reverse
    , convert
    , copyRet
    , copyAndFreeze
    , splitAt
    , xor
    , index
    , eq
    , constEq
    , any
    , all
    , append
    , concat
    ) where

import           Data.ByteArray.Types
import           Data.Memory.Internal.Compat
import           Data.Memory.Internal.Imports hiding (empty)
import           Data.Memory.PtrMethods
import           Data.Monoid
import           Foreign.Storable
import           Foreign.Ptr

import           Prelude hiding (length, take, drop, span, reverse, concat, replicate, splitAt, null, pred, last, any, all)
import qualified Prelude

#if defined(WITH_BYTESTRING_SUPPORT) && defined(WITH_BASEMENT_SUPPORT)
import qualified Data.ByteString as SPE (ByteString)
import qualified Basement.UArray as SPE (UArray)
import qualified Basement.Block  as SPE (Block)
#endif

-- | Allocate a new bytearray of specific size, and run the initializer on this memory
alloc :: ByteArray ba => Int -> (Ptr p -> IO ()) -> IO ba
alloc :: Int -> (Ptr p -> IO ()) -> IO ba
alloc Int
n Ptr p -> IO ()
f
    | Int
n Int -> Int -> Bool
forall a. Ord a => a -> a -> Bool
< Int
0     = Int -> (Ptr p -> IO ()) -> IO ba
forall ba p. ByteArray ba => Int -> (Ptr p -> IO ()) -> IO ba
alloc Int
0 Ptr p -> IO ()
f
    | Bool
otherwise = ((), ba) -> ba
forall a b. (a, b) -> b
snd (((), ba) -> ba) -> IO ((), ba) -> IO ba
forall (f :: * -> *) a b. Functor f => (a -> b) -> f a -> f b
`fmap` Int -> (Ptr p -> IO ()) -> IO ((), ba)
forall ba p a. ByteArray ba => Int -> (Ptr p -> IO a) -> IO (a, ba)
allocRet Int
n Ptr p -> IO ()
f
{-# INLINE alloc #-}

-- | Allocate a new bytearray of specific size, and run the initializer on this memory
create :: ByteArray ba => Int -> (Ptr p -> IO ()) -> IO ba
create :: Int -> (Ptr p -> IO ()) -> IO ba
create Int
n Ptr p -> IO ()
f = Int -> (Ptr p -> IO ()) -> IO ba
forall ba p. ByteArray ba => Int -> (Ptr p -> IO ()) -> IO ba
alloc Int
n Ptr p -> IO ()
f

-- | similar to 'alloc' but hide the allocation and initializer in a pure context
allocAndFreeze :: ByteArray a => Int -> (Ptr p -> IO ()) -> a
allocAndFreeze :: Int -> (Ptr p -> IO ()) -> a
allocAndFreeze Int
sz Ptr p -> IO ()
f = IO a -> a
forall a. IO a -> a
unsafeDoIO (Int -> (Ptr p -> IO ()) -> IO a
forall ba p. ByteArray ba => Int -> (Ptr p -> IO ()) -> IO ba
alloc Int
sz Ptr p -> IO ()
f)
{-# NOINLINE allocAndFreeze #-}

-- | similar to 'create' but hide the allocation and initializer in a pure context
unsafeCreate :: ByteArray a => Int -> (Ptr p -> IO ()) -> a
unsafeCreate :: Int -> (Ptr p -> IO ()) -> a
unsafeCreate Int
sz Ptr p -> IO ()
f = IO a -> a
forall a. IO a -> a
unsafeDoIO (Int -> (Ptr p -> IO ()) -> IO a
forall ba p. ByteArray ba => Int -> (Ptr p -> IO ()) -> IO ba
alloc Int
sz Ptr p -> IO ()
f)
{-# NOINLINE unsafeCreate #-}

inlineUnsafeCreate :: ByteArray a => Int -> (Ptr p -> IO ()) -> a
inlineUnsafeCreate :: Int -> (Ptr p -> IO ()) -> a
inlineUnsafeCreate !Int
sz Ptr p -> IO ()
f = IO a -> a
forall a. IO a -> a
unsafeDoIO (Int -> (Ptr p -> IO ()) -> IO a
forall ba p. ByteArray ba => Int -> (Ptr p -> IO ()) -> IO ba
alloc Int
sz Ptr p -> IO ()
f)
{-# INLINE inlineUnsafeCreate #-}

-- | Create an empty byte array
empty :: ByteArray a => a
empty :: a
empty = IO a -> a
forall a. IO a -> a
unsafeDoIO (Int -> (Ptr Any -> IO ()) -> IO a
forall ba p. ByteArray ba => Int -> (Ptr p -> IO ()) -> IO ba
alloc Int
0 ((Ptr Any -> IO ()) -> IO a) -> (Ptr Any -> IO ()) -> IO a
forall a b. (a -> b) -> a -> b
$ \Ptr Any
_ -> () -> IO ()
forall (m :: * -> *) a. Monad m => a -> m a
return ())

-- | Check if a byte array is empty
null :: ByteArrayAccess a => a -> Bool
null :: a -> Bool
null a
b = a -> Int
forall ba. ByteArrayAccess ba => ba -> Int
length a
b Int -> Int -> Bool
forall a. Eq a => a -> a -> Bool
== Int
0

-- | Pack a list of bytes into a bytearray
pack :: ByteArray a => [Word8] -> a
pack :: [Word8] -> a
pack [Word8]
l = Int -> (Ptr Word8 -> IO ()) -> a
forall a p. ByteArray a => Int -> (Ptr p -> IO ()) -> a
inlineUnsafeCreate ([Word8] -> Int
forall (t :: * -> *) a. Foldable t => t a -> Int
Prelude.length [Word8]
l) ([Word8] -> Ptr Word8 -> IO ()
forall b. Storable b => [b] -> Ptr b -> IO ()
fill [Word8]
l)
  where fill :: [b] -> Ptr b -> IO ()
fill []     Ptr b
_  = () -> IO ()
forall (m :: * -> *) a. Monad m => a -> m a
return ()
        fill (b
x:[b]
xs) !Ptr b
p = Ptr b -> b -> IO ()
forall a. Storable a => Ptr a -> a -> IO ()
poke Ptr b
p b
x IO () -> IO () -> IO ()
forall (m :: * -> *) a b. Monad m => m a -> m b -> m b
>> [b] -> Ptr b -> IO ()
fill [b]
xs (Ptr b
p Ptr b -> Int -> Ptr b
forall a b. Ptr a -> Int -> Ptr b
`plusPtr` Int
1)
        {-# INLINE fill #-}
{-# NOINLINE pack #-}

-- | Un-pack a bytearray into a list of bytes
unpack :: ByteArrayAccess a => a -> [Word8]
unpack :: a -> [Word8]
unpack a
bs = Int -> [Word8]
forall a. Storable a => Int -> [a]
loop Int
0
  where !len :: Int
len = a -> Int
forall ba. ByteArrayAccess ba => ba -> Int
length a
bs
        loop :: Int -> [a]
loop Int
i
            | Int
i Int -> Int -> Bool
forall a. Eq a => a -> a -> Bool
== Int
len  = []
            | Bool
otherwise =
                let !v :: a
v = IO a -> a
forall a. IO a -> a
unsafeDoIO (IO a -> a) -> IO a -> a
forall a b. (a -> b) -> a -> b
$ a -> (Ptr Any -> IO a) -> IO a
forall ba p a. ByteArrayAccess ba => ba -> (Ptr p -> IO a) -> IO a
withByteArray a
bs (\Ptr Any
p -> Ptr Any -> Int -> IO a
forall a b. Storable a => Ptr b -> Int -> IO a
peekByteOff Ptr Any
p Int
i)
                 in a
v a -> [a] -> [a]
forall a. a -> [a] -> [a]
: Int -> [a]
loop (Int
iInt -> Int -> Int
forall a. Num a => a -> a -> a
+Int
1)

-- | returns the first byte, and the remaining bytearray if the bytearray is not null
uncons :: ByteArray a => a -> Maybe (Word8, a)
uncons :: a -> Maybe (Word8, a)
uncons a
a
    | a -> Bool
forall a. ByteArrayAccess a => a -> Bool
null a
a    = Maybe (Word8, a)
forall a. Maybe a
Nothing
    | Bool
otherwise = (Word8, a) -> Maybe (Word8, a)
forall a. a -> Maybe a
Just (a -> Int -> Word8
forall a. ByteArrayAccess a => a -> Int -> Word8
index a
a Int
0, Int -> a -> a
forall bs. ByteArray bs => Int -> bs -> bs
drop Int
1 a
a)

-- | Create a byte array from a single byte
singleton :: ByteArray a => Word8 -> a
singleton :: Word8 -> a
singleton Word8
b = Int -> (Ptr Any -> IO ()) -> a
forall a p. ByteArray a => Int -> (Ptr p -> IO ()) -> a
unsafeCreate Int
1 (\Ptr Any
p -> Ptr Any -> Int -> Word8 -> IO ()
forall a b. Storable a => Ptr b -> Int -> a -> IO ()
pokeByteOff Ptr Any
p Int
0 Word8
b)

-- | prepend a single byte to a byte array
cons :: ByteArray a => Word8 -> a -> a
cons :: Word8 -> a -> a
cons Word8
b a
ba = Int -> (Ptr Any -> IO ()) -> a
forall a p. ByteArray a => Int -> (Ptr p -> IO ()) -> a
unsafeCreate (Int
len Int -> Int -> Int
forall a. Num a => a -> a -> a
+ Int
1) ((Ptr Any -> IO ()) -> a) -> (Ptr Any -> IO ()) -> a
forall a b. (a -> b) -> a -> b
$ \Ptr Any
d -> a -> (Ptr Word8 -> IO ()) -> IO ()
forall ba p a. ByteArrayAccess ba => ba -> (Ptr p -> IO a) -> IO a
withByteArray a
ba ((Ptr Word8 -> IO ()) -> IO ()) -> (Ptr Word8 -> IO ()) -> IO ()
forall a b. (a -> b) -> a -> b
$ \Ptr Word8
s -> do
    Ptr Any -> Int -> Word8 -> IO ()
forall a b. Storable a => Ptr b -> Int -> a -> IO ()
pokeByteOff Ptr Any
d Int
0 Word8
b
    Ptr Word8 -> Ptr Word8 -> Int -> IO ()
memCopy (Ptr Any
d Ptr Any -> Int -> Ptr Word8
forall a b. Ptr a -> Int -> Ptr b
`plusPtr` Int
1) Ptr Word8
s Int
len
  where len :: Int
len = a -> Int
forall ba. ByteArrayAccess ba => ba -> Int
length a
ba

-- | append a single byte to a byte array
snoc :: ByteArray a =>  a -> Word8 -> a
snoc :: a -> Word8 -> a
snoc a
ba Word8
b = Int -> (Ptr Word8 -> IO ()) -> a
forall a p. ByteArray a => Int -> (Ptr p -> IO ()) -> a
unsafeCreate (Int
len Int -> Int -> Int
forall a. Num a => a -> a -> a
+ Int
1) ((Ptr Word8 -> IO ()) -> a) -> (Ptr Word8 -> IO ()) -> a
forall a b. (a -> b) -> a -> b
$ \Ptr Word8
d -> a -> (Ptr Word8 -> IO ()) -> IO ()
forall ba p a. ByteArrayAccess ba => ba -> (Ptr p -> IO a) -> IO a
withByteArray a
ba ((Ptr Word8 -> IO ()) -> IO ()) -> (Ptr Word8 -> IO ()) -> IO ()
forall a b. (a -> b) -> a -> b
$ \Ptr Word8
s -> do
    Ptr Word8 -> Ptr Word8 -> Int -> IO ()
memCopy Ptr Word8
d Ptr Word8
s Int
len
    Ptr Word8 -> Int -> Word8 -> IO ()
forall a b. Storable a => Ptr b -> Int -> a -> IO ()
pokeByteOff Ptr Word8
d Int
len Word8
b
  where len :: Int
len = a -> Int
forall ba. ByteArrayAccess ba => ba -> Int
length a
ba

-- | Create a xor of bytes between a and b.
--
-- the returns byte array is the size of the smallest input.
xor :: (ByteArrayAccess a, ByteArrayAccess b, ByteArray c) => a -> b -> c
xor :: a -> b -> c
xor a
a b
b =
    Int -> (Ptr Word8 -> IO ()) -> c
forall a p. ByteArray a => Int -> (Ptr p -> IO ()) -> a
unsafeCreate Int
n ((Ptr Word8 -> IO ()) -> c) -> (Ptr Word8 -> IO ()) -> c
forall a b. (a -> b) -> a -> b
$ \Ptr Word8
pc ->
    a -> (Ptr Word8 -> IO ()) -> IO ()
forall ba p a. ByteArrayAccess ba => ba -> (Ptr p -> IO a) -> IO a
withByteArray a
a  ((Ptr Word8 -> IO ()) -> IO ()) -> (Ptr Word8 -> IO ()) -> IO ()
forall a b. (a -> b) -> a -> b
$ \Ptr Word8
pa ->
    b -> (Ptr Word8 -> IO ()) -> IO ()
forall ba p a. ByteArrayAccess ba => ba -> (Ptr p -> IO a) -> IO a
withByteArray b
b  ((Ptr Word8 -> IO ()) -> IO ()) -> (Ptr Word8 -> IO ()) -> IO ()
forall a b. (a -> b) -> a -> b
$ \Ptr Word8
pb ->
        Ptr Word8 -> Ptr Word8 -> Ptr Word8 -> Int -> IO ()
memXor Ptr Word8
pc Ptr Word8
pa Ptr Word8
pb Int
n
  where
        n :: Int
n  = Int -> Int -> Int
forall a. Ord a => a -> a -> a
min Int
la Int
lb
        la :: Int
la = a -> Int
forall ba. ByteArrayAccess ba => ba -> Int
length a
a
        lb :: Int
lb = b -> Int
forall ba. ByteArrayAccess ba => ba -> Int
length b
b

-- | return a specific byte indexed by a number from 0 in a bytearray
--
-- unsafe, no bound checking are done
index :: ByteArrayAccess a => a -> Int -> Word8
index :: a -> Int -> Word8
index a
b Int
i = IO Word8 -> Word8
forall a. IO a -> a
unsafeDoIO (IO Word8 -> Word8) -> IO Word8 -> Word8
forall a b. (a -> b) -> a -> b
$ a -> (Ptr Any -> IO Word8) -> IO Word8
forall ba p a. ByteArrayAccess ba => ba -> (Ptr p -> IO a) -> IO a
withByteArray a
b ((Ptr Any -> IO Word8) -> IO Word8)
-> (Ptr Any -> IO Word8) -> IO Word8
forall a b. (a -> b) -> a -> b
$ \Ptr Any
p -> Ptr Word8 -> IO Word8
forall a. Storable a => Ptr a -> IO a
peek (Ptr Any
p Ptr Any -> Int -> Ptr Word8
forall a b. Ptr a -> Int -> Ptr b
`plusPtr` Int
i)

-- | Split a bytearray at a specific length in two bytearray
splitAt :: ByteArray bs => Int -> bs -> (bs, bs)
splitAt :: Int -> bs -> (bs, bs)
splitAt Int
n bs
bs
    | Int
n Int -> Int -> Bool
forall a. Ord a => a -> a -> Bool
<= Int
0    = (bs
forall a. ByteArray a => a
empty, bs
bs)
    | Int
n Int -> Int -> Bool
forall a. Ord a => a -> a -> Bool
>= Int
len  = (bs
bs, bs
forall a. ByteArray a => a
empty)
    | Bool
otherwise = IO (bs, bs) -> (bs, bs)
forall a. IO a -> a
unsafeDoIO (IO (bs, bs) -> (bs, bs)) -> IO (bs, bs) -> (bs, bs)
forall a b. (a -> b) -> a -> b
$ do
        bs -> (Ptr Word8 -> IO (bs, bs)) -> IO (bs, bs)
forall ba p a. ByteArrayAccess ba => ba -> (Ptr p -> IO a) -> IO a
withByteArray bs
bs ((Ptr Word8 -> IO (bs, bs)) -> IO (bs, bs))
-> (Ptr Word8 -> IO (bs, bs)) -> IO (bs, bs)
forall a b. (a -> b) -> a -> b
$ \Ptr Word8
p -> do
            bs
b1 <- Int -> (Ptr Word8 -> IO ()) -> IO bs
forall ba p. ByteArray ba => Int -> (Ptr p -> IO ()) -> IO ba
alloc Int
n ((Ptr Word8 -> IO ()) -> IO bs) -> (Ptr Word8 -> IO ()) -> IO bs
forall a b. (a -> b) -> a -> b
$ \Ptr Word8
r -> Ptr Word8 -> Ptr Word8 -> Int -> IO ()
memCopy Ptr Word8
r Ptr Word8
p Int
n
            bs
b2 <- Int -> (Ptr Word8 -> IO ()) -> IO bs
forall ba p. ByteArray ba => Int -> (Ptr p -> IO ()) -> IO ba
alloc (Int
len Int -> Int -> Int
forall a. Num a => a -> a -> a
- Int
n) ((Ptr Word8 -> IO ()) -> IO bs) -> (Ptr Word8 -> IO ()) -> IO bs
forall a b. (a -> b) -> a -> b
$ \Ptr Word8
r -> Ptr Word8 -> Ptr Word8 -> Int -> IO ()
memCopy Ptr Word8
r (Ptr Word8
p Ptr Word8 -> Int -> Ptr Word8
forall a b. Ptr a -> Int -> Ptr b
`plusPtr` Int
n) (Int
len Int -> Int -> Int
forall a. Num a => a -> a -> a
- Int
n)
            (bs, bs) -> IO (bs, bs)
forall (m :: * -> *) a. Monad m => a -> m a
return (bs
b1, bs
b2)
  where len :: Int
len = bs -> Int
forall ba. ByteArrayAccess ba => ba -> Int
length bs
bs

-- | Take the first @n@ byte of a bytearray
take :: ByteArray bs => Int -> bs -> bs
take :: Int -> bs -> bs
take Int
n bs
bs
    | Int
n Int -> Int -> Bool
forall a. Ord a => a -> a -> Bool
<= Int
0    = bs
forall a. ByteArray a => a
empty
    | Bool
otherwise = Int -> (Ptr Word8 -> IO ()) -> bs
forall a p. ByteArray a => Int -> (Ptr p -> IO ()) -> a
unsafeCreate Int
m ((Ptr Word8 -> IO ()) -> bs) -> (Ptr Word8 -> IO ()) -> bs
forall a b. (a -> b) -> a -> b
$ \Ptr Word8
d -> bs -> (Ptr Word8 -> IO ()) -> IO ()
forall ba p a. ByteArrayAccess ba => ba -> (Ptr p -> IO a) -> IO a
withByteArray bs
bs ((Ptr Word8 -> IO ()) -> IO ()) -> (Ptr Word8 -> IO ()) -> IO ()
forall a b. (a -> b) -> a -> b
$ \Ptr Word8
s -> Ptr Word8 -> Ptr Word8 -> Int -> IO ()
memCopy Ptr Word8
d Ptr Word8
s Int
m
  where
    !m :: Int
m   = Int -> Int -> Int
forall a. Ord a => a -> a -> a
min Int
len Int
n
    !len :: Int
len = bs -> Int
forall ba. ByteArrayAccess ba => ba -> Int
length bs
bs

-- | drop the first @n@ byte of a bytearray
drop :: ByteArray bs => Int -> bs -> bs
drop :: Int -> bs -> bs
drop Int
n bs
bs
    | Int
n Int -> Int -> Bool
forall a. Ord a => a -> a -> Bool
<= Int
0    = bs
bs
    | Int
nb Int -> Int -> Bool
forall a. Eq a => a -> a -> Bool
== Int
0   = bs
forall a. ByteArray a => a
empty
    | Bool
otherwise = Int -> (Ptr Word8 -> IO ()) -> bs
forall a p. ByteArray a => Int -> (Ptr p -> IO ()) -> a
unsafeCreate Int
nb ((Ptr Word8 -> IO ()) -> bs) -> (Ptr Word8 -> IO ()) -> bs
forall a b. (a -> b) -> a -> b
$ \Ptr Word8
d -> bs -> (Ptr Any -> IO ()) -> IO ()
forall ba p a. ByteArrayAccess ba => ba -> (Ptr p -> IO a) -> IO a
withByteArray bs
bs ((Ptr Any -> IO ()) -> IO ()) -> (Ptr Any -> IO ()) -> IO ()
forall a b. (a -> b) -> a -> b
$ \Ptr Any
s -> Ptr Word8 -> Ptr Word8 -> Int -> IO ()
memCopy Ptr Word8
d (Ptr Any
s Ptr Any -> Int -> Ptr Word8
forall a b. Ptr a -> Int -> Ptr b
`plusPtr` Int
ofs) Int
nb
  where
    ofs :: Int
ofs = Int -> Int -> Int
forall a. Ord a => a -> a -> a
min Int
len Int
n
    nb :: Int
nb  = Int
len Int -> Int -> Int
forall a. Num a => a -> a -> a
- Int
ofs
    len :: Int
len = bs -> Int
forall ba. ByteArrayAccess ba => ba -> Int
length bs
bs

-- | Split a bytearray at the point where @pred@ becomes invalid
span :: ByteArray bs => (Word8 -> Bool) -> bs -> (bs, bs)
span :: (Word8 -> Bool) -> bs -> (bs, bs)
span Word8 -> Bool
pred bs
bs
    | bs -> Bool
forall a. ByteArrayAccess a => a -> Bool
null bs
bs   = (bs
bs, bs
bs)
    | Bool
otherwise = let n :: Int
n = Int -> Int
loop Int
0 in (Int -> bs -> bs
forall bs. ByteArray bs => Int -> bs -> bs
take Int
n bs
bs, Int -> bs -> bs
forall bs. ByteArray bs => Int -> bs -> bs
drop Int
n bs
bs)
  where loop :: Int -> Int
loop !Int
i
            | Int
i Int -> Int -> Bool
forall a. Ord a => a -> a -> Bool
>= Int
len          = Int
len
            | Word8 -> Bool
pred (bs -> Int -> Word8
forall a. ByteArrayAccess a => a -> Int -> Word8
index bs
bs Int
i) = Int -> Int
loop (Int
iInt -> Int -> Int
forall a. Num a => a -> a -> a
+Int
1)
            | Bool
otherwise         = Int
i
        len :: Int
len = bs -> Int
forall ba. ByteArrayAccess ba => ba -> Int
length bs
bs

-- | Reverse a bytearray
reverse :: ByteArray bs => bs -> bs
reverse :: bs -> bs
reverse bs
bs = Int -> (Ptr Word8 -> IO ()) -> bs
forall a p. ByteArray a => Int -> (Ptr p -> IO ()) -> a
unsafeCreate Int
n ((Ptr Word8 -> IO ()) -> bs) -> (Ptr Word8 -> IO ()) -> bs
forall a b. (a -> b) -> a -> b
$ \Ptr Word8
d -> bs -> (Ptr Word8 -> IO ()) -> IO ()
forall ba p a. ByteArrayAccess ba => ba -> (Ptr p -> IO a) -> IO a
withByteArray bs
bs ((Ptr Word8 -> IO ()) -> IO ()) -> (Ptr Word8 -> IO ()) -> IO ()
forall a b. (a -> b) -> a -> b
$ \Ptr Word8
s -> Ptr Word8 -> Ptr Word8 -> Int -> IO ()
memReverse Ptr Word8
d Ptr Word8
s Int
n
  where n :: Int
n = bs -> Int
forall ba. ByteArrayAccess ba => ba -> Int
length bs
bs

-- | Concatenate bytearray into a larger bytearray
concat :: (ByteArrayAccess bin, ByteArray bout) => [bin] -> bout
concat :: [bin] -> bout
concat [bin]
l = Int -> (Ptr Any -> IO ()) -> bout
forall a p. ByteArray a => Int -> (Ptr p -> IO ()) -> a
unsafeCreate Int
retLen ([bin] -> Ptr Any -> IO ()
forall ba b. ByteArrayAccess ba => [ba] -> Ptr b -> IO ()
loopCopy [bin]
l)
  where
    retLen :: Int
retLen = [Int] -> Int
forall (t :: * -> *) a. (Foldable t, Num a) => t a -> a
sum ([Int] -> Int) -> [Int] -> Int
forall a b. (a -> b) -> a -> b
$ (bin -> Int) -> [bin] -> [Int]
forall a b. (a -> b) -> [a] -> [b]
map bin -> Int
forall ba. ByteArrayAccess ba => ba -> Int
length [bin]
l

    loopCopy :: [ba] -> Ptr b -> IO ()
loopCopy []     Ptr b
_   = () -> IO ()
forall (m :: * -> *) a. Monad m => a -> m a
return ()
    loopCopy (ba
x:[ba]
xs) Ptr b
dst = do
        ba -> Ptr b -> IO ()
forall ba p. ByteArrayAccess ba => ba -> Ptr p -> IO ()
copyByteArrayToPtr ba
x Ptr b
dst
        [ba] -> Ptr b -> IO ()
loopCopy [ba]
xs (Ptr b
dst Ptr b -> Int -> Ptr b
forall a b. Ptr a -> Int -> Ptr b
`plusPtr` Int
chunkLen)
      where
        !chunkLen :: Int
chunkLen = ba -> Int
forall ba. ByteArrayAccess ba => ba -> Int
length ba
x

-- | append one bytearray to the other
append :: ByteArray bs => bs -> bs -> bs
append :: bs -> bs -> bs
append = bs -> bs -> bs
forall a. Monoid a => a -> a -> a
mappend

-- | Duplicate a bytearray into another bytearray, and run an initializer on it
copy :: (ByteArrayAccess bs1, ByteArray bs2) => bs1 -> (Ptr p -> IO ()) -> IO bs2
copy :: bs1 -> (Ptr p -> IO ()) -> IO bs2
copy bs1
bs Ptr p -> IO ()
f =
    Int -> (Ptr Any -> IO ()) -> IO bs2
forall ba p. ByteArray ba => Int -> (Ptr p -> IO ()) -> IO ba
alloc (bs1 -> Int
forall ba. ByteArrayAccess ba => ba -> Int
length bs1
bs) ((Ptr Any -> IO ()) -> IO bs2) -> (Ptr Any -> IO ()) -> IO bs2
forall a b. (a -> b) -> a -> b
$ \Ptr Any
d -> do
        bs1 -> Ptr Any -> IO ()
forall ba p. ByteArrayAccess ba => ba -> Ptr p -> IO ()
copyByteArrayToPtr bs1
bs Ptr Any
d
        Ptr p -> IO ()
f (Ptr Any -> Ptr p
forall a b. Ptr a -> Ptr b
castPtr Ptr Any
d)

-- | Similar to 'copy' but also provide a way to return a value from the initializer
copyRet :: (ByteArrayAccess bs1, ByteArray bs2) => bs1 -> (Ptr p -> IO a) -> IO (a, bs2)
copyRet :: bs1 -> (Ptr p -> IO a) -> IO (a, bs2)
copyRet bs1
bs Ptr p -> IO a
f =
    Int -> (Ptr Any -> IO a) -> IO (a, bs2)
forall ba p a. ByteArray ba => Int -> (Ptr p -> IO a) -> IO (a, ba)
allocRet (bs1 -> Int
forall ba. ByteArrayAccess ba => ba -> Int
length bs1
bs) ((Ptr Any -> IO a) -> IO (a, bs2))
-> (Ptr Any -> IO a) -> IO (a, bs2)
forall a b. (a -> b) -> a -> b
$ \Ptr Any
d -> do
        bs1 -> Ptr Any -> IO ()
forall ba p. ByteArrayAccess ba => ba -> Ptr p -> IO ()
copyByteArrayToPtr bs1
bs Ptr Any
d
        Ptr p -> IO a
f (Ptr Any -> Ptr p
forall a b. Ptr a -> Ptr b
castPtr Ptr Any
d)

-- | Similiar to 'copy' but expect the resulting bytearray in a pure context
copyAndFreeze :: (ByteArrayAccess bs1, ByteArray bs2) => bs1 -> (Ptr p -> IO ()) -> bs2
copyAndFreeze :: bs1 -> (Ptr p -> IO ()) -> bs2
copyAndFreeze bs1
bs Ptr p -> IO ()
f =
    Int -> (Ptr Any -> IO ()) -> bs2
forall a p. ByteArray a => Int -> (Ptr p -> IO ()) -> a
inlineUnsafeCreate (bs1 -> Int
forall ba. ByteArrayAccess ba => ba -> Int
length bs1
bs) ((Ptr Any -> IO ()) -> bs2) -> (Ptr Any -> IO ()) -> bs2
forall a b. (a -> b) -> a -> b
$ \Ptr Any
d -> do
        bs1 -> Ptr Any -> IO ()
forall ba p. ByteArrayAccess ba => ba -> Ptr p -> IO ()
copyByteArrayToPtr bs1
bs Ptr Any
d
        Ptr p -> IO ()
f (Ptr Any -> Ptr p
forall a b. Ptr a -> Ptr b
castPtr Ptr Any
d)
{-# NOINLINE copyAndFreeze #-}

-- | Create a bytearray of a specific size containing a repeated byte value
replicate :: ByteArray ba => Int -> Word8 -> ba
replicate :: Int -> Word8 -> ba
replicate Int
0 Word8
_ = ba
forall a. ByteArray a => a
empty
replicate Int
n Word8
b
    | Int
n Int -> Int -> Bool
forall a. Ord a => a -> a -> Bool
< Int
0     = ba
forall a. ByteArray a => a
empty
    | Bool
otherwise = Int -> (Ptr Word8 -> IO ()) -> ba
forall a p. ByteArray a => Int -> (Ptr p -> IO ()) -> a
inlineUnsafeCreate Int
n ((Ptr Word8 -> IO ()) -> ba) -> (Ptr Word8 -> IO ()) -> ba
forall a b. (a -> b) -> a -> b
$ \Ptr Word8
ptr -> Ptr Word8 -> Word8 -> Int -> IO ()
memSet Ptr Word8
ptr Word8
b Int
n
{-# NOINLINE replicate #-}

-- | Create a bytearray of a specific size initialized to 0
zero :: ByteArray ba => Int -> ba
zero :: Int -> ba
zero Int
0 = ba
forall a. ByteArray a => a
empty
zero Int
n
    | Int
n Int -> Int -> Bool
forall a. Ord a => a -> a -> Bool
< Int
0     = ba
forall a. ByteArray a => a
empty
    | Bool
otherwise = Int -> (Ptr Word8 -> IO ()) -> ba
forall a p. ByteArray a => Int -> (Ptr p -> IO ()) -> a
unsafeCreate Int
n ((Ptr Word8 -> IO ()) -> ba) -> (Ptr Word8 -> IO ()) -> ba
forall a b. (a -> b) -> a -> b
$ \Ptr Word8
ptr -> Ptr Word8 -> Word8 -> Int -> IO ()
memSet Ptr Word8
ptr Word8
0 Int
n
{-# NOINLINE zero #-}

-- | Check if two bytearray are equals
--
-- This is not constant time, as soon some byte differs the function will
-- returns. use 'constEq' in sensitive context where timing matters.
eq :: (ByteArrayAccess bs1, ByteArrayAccess bs2) => bs1 -> bs2 -> Bool
eq :: bs1 -> bs2 -> Bool
eq bs1
b1 bs2
b2
    | Int
l1 Int -> Int -> Bool
forall a. Eq a => a -> a -> Bool
/= Int
l2  = Bool
False
    | Bool
otherwise = IO Bool -> Bool
forall a. IO a -> a
unsafeDoIO (IO Bool -> Bool) -> IO Bool -> Bool
forall a b. (a -> b) -> a -> b
$ bs1 -> (Ptr Word8 -> IO Bool) -> IO Bool
forall ba p a. ByteArrayAccess ba => ba -> (Ptr p -> IO a) -> IO a
withByteArray bs1
b1 ((Ptr Word8 -> IO Bool) -> IO Bool)
-> (Ptr Word8 -> IO Bool) -> IO Bool
forall a b. (a -> b) -> a -> b
$ \Ptr Word8
p1 -> bs2 -> (Ptr Word8 -> IO Bool) -> IO Bool
forall ba p a. ByteArrayAccess ba => ba -> (Ptr p -> IO a) -> IO a
withByteArray bs2
b2 ((Ptr Word8 -> IO Bool) -> IO Bool)
-> (Ptr Word8 -> IO Bool) -> IO Bool
forall a b. (a -> b) -> a -> b
$ \Ptr Word8
p2 -> Ptr Word8 -> Ptr Word8 -> Int -> IO Bool
memEqual Ptr Word8
p1 Ptr Word8
p2 Int
l1
  where
    l1 :: Int
l1 = bs1 -> Int
forall ba. ByteArrayAccess ba => ba -> Int
length bs1
b1
    l2 :: Int
l2 = bs2 -> Int
forall ba. ByteArrayAccess ba => ba -> Int
length bs2
b2

-- | A constant time equality test for 2 ByteArrayAccess values.
--
-- If values are of 2 different sizes, the function will abort early
-- without comparing any bytes.
--
-- compared to == , this function will go over all the bytes
-- present before yielding a result even when knowing the
-- overall result early in the processing.
constEq :: (ByteArrayAccess bs1, ByteArrayAccess bs2) => bs1 -> bs2 -> Bool
constEq :: bs1 -> bs2 -> Bool
constEq bs1
b1 bs2
b2
    | Int
l1 Int -> Int -> Bool
forall a. Eq a => a -> a -> Bool
/= Int
l2  = Bool
False
    | Bool
otherwise = IO Bool -> Bool
forall a. IO a -> a
unsafeDoIO (IO Bool -> Bool) -> IO Bool -> Bool
forall a b. (a -> b) -> a -> b
$ bs1 -> (Ptr Word8 -> IO Bool) -> IO Bool
forall ba p a. ByteArrayAccess ba => ba -> (Ptr p -> IO a) -> IO a
withByteArray bs1
b1 ((Ptr Word8 -> IO Bool) -> IO Bool)
-> (Ptr Word8 -> IO Bool) -> IO Bool
forall a b. (a -> b) -> a -> b
$ \Ptr Word8
p1 -> bs2 -> (Ptr Word8 -> IO Bool) -> IO Bool
forall ba p a. ByteArrayAccess ba => ba -> (Ptr p -> IO a) -> IO a
withByteArray bs2
b2 ((Ptr Word8 -> IO Bool) -> IO Bool)
-> (Ptr Word8 -> IO Bool) -> IO Bool
forall a b. (a -> b) -> a -> b
$ \Ptr Word8
p2 -> Ptr Word8 -> Ptr Word8 -> Int -> IO Bool
memConstEqual Ptr Word8
p1 Ptr Word8
p2 Int
l1
  where
    !l1 :: Int
l1 = bs1 -> Int
forall ba. ByteArrayAccess ba => ba -> Int
length bs1
b1
    !l2 :: Int
l2 = bs2 -> Int
forall ba. ByteArrayAccess ba => ba -> Int
length bs2
b2

-- | Check if any element of a byte array satisfies a predicate
any :: (ByteArrayAccess ba) => (Word8 -> Bool) -> ba -> Bool
any :: (Word8 -> Bool) -> ba -> Bool
any Word8 -> Bool
f ba
b
    | ba -> Bool
forall a. ByteArrayAccess a => a -> Bool
null ba
b    = Bool
False
    | Bool
otherwise = IO Bool -> Bool
forall a. IO a -> a
unsafeDoIO (IO Bool -> Bool) -> IO Bool -> Bool
forall a b. (a -> b) -> a -> b
$ ba -> (Ptr Any -> IO Bool) -> IO Bool
forall ba p a. ByteArrayAccess ba => ba -> (Ptr p -> IO a) -> IO a
withByteArray ba
b ((Ptr Any -> IO Bool) -> IO Bool)
-> (Ptr Any -> IO Bool) -> IO Bool
forall a b. (a -> b) -> a -> b
$ \Ptr Any
p -> Ptr Any -> Int -> IO Bool
forall b. Ptr b -> Int -> IO Bool
loop Ptr Any
p Int
0
  where
    len :: Int
len = ba -> Int
forall ba. ByteArrayAccess ba => ba -> Int
length ba
b
    loop :: Ptr b -> Int -> IO Bool
loop Ptr b
p Int
i
        | Int
i Int -> Int -> Bool
forall a. Eq a => a -> a -> Bool
== Int
len  = Bool -> IO Bool
forall (m :: * -> *) a. Monad m => a -> m a
return Bool
False
        | Bool
otherwise = do
            Word8
w <- Ptr b -> Int -> IO Word8
forall a b. Storable a => Ptr b -> Int -> IO a
peekByteOff Ptr b
p Int
i
            if Word8 -> Bool
f Word8
w then Bool -> IO Bool
forall (m :: * -> *) a. Monad m => a -> m a
return Bool
True else Ptr b -> Int -> IO Bool
loop Ptr b
p (Int
iInt -> Int -> Int
forall a. Num a => a -> a -> a
+Int
1)

-- | Check if all elements of a byte array satisfy a predicate
all :: (ByteArrayAccess ba) => (Word8 -> Bool) -> ba -> Bool
all :: (Word8 -> Bool) -> ba -> Bool
all Word8 -> Bool
f ba
b = Bool -> Bool
not ((Word8 -> Bool) -> ba -> Bool
forall ba. ByteArrayAccess ba => (Word8 -> Bool) -> ba -> Bool
any (Bool -> Bool
not (Bool -> Bool) -> (Word8 -> Bool) -> Word8 -> Bool
forall b c a. (b -> c) -> (a -> b) -> a -> c
. Word8 -> Bool
f) ba
b)

-- | Convert a bytearray to another type of bytearray
convert :: (ByteArrayAccess bin, ByteArray bout) => bin -> bout
convert :: bin -> bout
convert bin
bs = Int -> (Ptr Any -> IO ()) -> bout
forall a p. ByteArray a => Int -> (Ptr p -> IO ()) -> a
inlineUnsafeCreate (bin -> Int
forall ba. ByteArrayAccess ba => ba -> Int
length bin
bs) (bin -> Ptr Any -> IO ()
forall ba p. ByteArrayAccess ba => ba -> Ptr p -> IO ()
copyByteArrayToPtr bin
bs)
#if defined(WITH_BYTESTRING_SUPPORT) && defined(WITH_BASEMENT_SUPPORT)
{-# SPECIALIZE convert :: SPE.ByteString -> SPE.UArray Word8 #-}
{-# SPECIALIZE convert :: SPE.UArray Word8 -> SPE.ByteString #-}
{-# SPECIALIZE convert :: SPE.ByteString -> SPE.Block Word8 #-}
{-# SPECIALIZE convert :: SPE.Block Word8 -> SPE.ByteString #-}
#endif