{-# OPTIONS_GHC -Wall -fwarn-tabs #-}
{-# OPTIONS_HADDOCK hide #-}
{-# LANGUAGE CPP, BangPatterns #-}
#if __GLASGOW_HASKELL__ >= 701
-- Neither 'unsafeDupablePerformIO' nor 'Data.ByteString.Internal' is safe.
{-# LANGUAGE Trustworthy #-}
#endif
------------------------------------------------------------
--                                              ~ 2022.02.27
-- |
-- Module      :  Data.Trie.Internal.ByteString
-- Copyright   :  2008--2023 wren romano
-- License     :  BSD-3-Clause
-- Maintainer  :  wren@cpan.org
-- Stability   :  stable
-- Portability :  GHC-only
--
-- Helper functions on 'ByteString's for "Data.Trie.Internal".
------------------------------------------------------------

module Data.Trie.Internal.ByteString
    ( ByteString, ByteStringElem
    , breakMaximalPrefix
    , RevLazyByteString(..), (+>!), (+>?), fromStrict, toStrict
        -- TODO: we want to export the 'Nil' constructor; but
        -- do we want to export the patterns?
    ) where

import qualified Data.ByteString          as S
import qualified Data.ByteString.Internal as S
import Data.ByteString.Internal (ByteString(PS))
import Data.Word
import Foreign.ForeignPtr       (ForeignPtr)
#if MIN_VERSION_base(4,15,0)
-- [aka GHC 9.0.1]:
import GHC.ForeignPtr           (unsafeWithForeignPtr)
#else
import Foreign.ForeignPtr       (withForeignPtr)
#endif
import Foreign.Ptr              (Ptr, plusPtr)
import Foreign.Storable         (Storable(..))
-- This module name is since @__GLASGOW_HASKELL__ >= 611@.
import GHC.IO                   (unsafeDupablePerformIO)

------------------------------------------------------------
#if !(MIN_VERSION_base(4,15,0))
-- bytestring-0.10.12.1 and 0.11.1.0 use and export this definition;
-- however neither 0.10.12.0 nor 0.11.0.0 define nor use it.So,
-- rather than dealing with all that nonsense, we'll just do it
-- ourselves.
unsafeWithForeignPtr :: ForeignPtr a -> (Ptr a -> IO b) -> IO b
unsafeWithForeignPtr = withForeignPtr
#endif


------------------------------------------------------------
------------------------------------------------------------
-- | Associated type of 'ByteString'
type ByteStringElem = Word8


------------------------------------------------------------
-- The @since annotation is for when this got re-exported from
-- "Data.Trie.Internal".
--
-- | Returns the longest shared prefix and the two remaining suffixes
-- for a pair of strings.  This function performs no allocation\/copying,
-- it simply returns slices\/views of the arguments.
--
-- * @s ≡ (\\(pre,s',z') -> pre '<>' s') ('breakMaximalPrefix' s z)@
-- * @z ≡ (\\(pre,s',z') -> pre '<>' z') ('breakMaximalPrefix' s z)@
--
-- @since 0.2.2
breakMaximalPrefix
    :: ByteString
    -> ByteString
    -> (ByteString, ByteString, ByteString)
--
-- [Implementation Notes]
--
-- * We've had to define 'strictTriple' and use BangPatterns to
--   keep GHC from wrapping all the returned triples in
--   ghc-prim:'GHC.Magic.lazy'.  Not sure how much this actually
--   helps performance, but it's a stepping stone towards defining
--   a custom result type which unpacks the three ByteStrings.  And
--   given that GHC's worker-wrapper transform generates a worker
--   that returns an unboxed tuple and yet internally does construct
--   the tuple, this suggests that using a custom return type should
--   help performance.
--
-- * TODO: the result of the inlined 'indexOfDifference' is still
--   being wrapped in ghc-prim:'GHC.Magic.lazy'; but nothing I can
--   do seems to change that.  Is it something about the
--   'unsafeDupablePerformIO' or what?  Would changing it even help
--   performance?
--
-- * The first two cases can safely be allowed to fall through to
--   the @i <= 0@ case. After inlining, there shouldn't be any
--   function-call overhead for letting 'goByte' do the comparison
--   instead.  The only difference is that the @i <= 0@ case will
--   hold onto @s0@/@s1@ rather than replacing them by 'S.empty'.
--   Unfortunately, that difference in liveness seems to result in
--   slightly worse performance.
--   TODO: a better benchmark than just running the test suite.
--
-- * The 'unsafeWithForeignPtr' allows for more aggressive optimization
--   than 'withForeignPtr', since it encodes the knowledge that the
--   continuation cannot diverge (loop, or throw exceptions).  In
--   particular, without this, the call to 'min' will get hoisted
--   above the inner 'withForeignPtr' and the call to 'indexOfDifference'
--   will be duplicated in both branches of the 'min'; and since
--   'indexOfDifference' will get inlined (recursive 'goBytes' and
--   all), that's a lot of code duplication.  However, for whatever
--   reason the 'unsafeWithForeignPtr' version actually seems to
--   result in slightly worse performance (0.2~2% on the test suite).
--   TODO: a better benchmark than just running the test suite.
--   TODO: if that hoisting actually does help, then perhaps manually
--     lift the 'max' above both 'withForeignPtr' and manually
--     express the branch duplication.
--   TODO: Also consider whether this might be relevant:
--     <https://gitlab.haskell.org/ghc/ghc/-/issues/16556>
--
-- * TODO: should we yield to the accursed call of
--     'Data.ByteString.Internal.accursedUnutterablePerformIO'?
--     Recent versions of bytestring export it, so we wouldn't
--     even need to copy the accursed incantation itself.  Regarding
--     correctness, probably the closest thing to compare against
--     are these bugs against 'S.elemIndices':
--     <https://gitlab.haskell.org/ghc/ghc/-/issues/3487>
--     <https://gitlab.haskell.org/ghc/ghc/-/issues/3486>
--
-- * TODO: re-investigate performance of lifting the non-IO stuff
--     out of the scope of the 'unsafeDupablePerformIO', vs leaving
--     it within that scope.
--
breakMaximalPrefix :: ByteString -> ByteString -> (ByteString, ByteString, ByteString)
breakMaximalPrefix
    s0 :: ByteString
s0@(PS ForeignPtr Word8
fp0 Int
off0 Int
len0)
    s1 :: ByteString
s1@(PS ForeignPtr Word8
fp1 Int
off1 Int
len1)
    | Int
len0 Int -> Int -> Bool
forall a. Ord a => a -> a -> Bool
<= Int
0 = ByteString
-> ByteString -> ByteString -> (ByteString, ByteString, ByteString)
strictTriple ByteString
S.empty ByteString
S.empty ByteString
s1
    | Int
len1 Int -> Int -> Bool
forall a. Ord a => a -> a -> Bool
<= Int
0 = ByteString
-> ByteString -> ByteString -> (ByteString, ByteString, ByteString)
strictTriple ByteString
S.empty ByteString
s0      ByteString
S.empty
    | Bool
otherwise =
        let i :: Int
i = IO Int -> Int
forall a. IO a -> a
unsafeDupablePerformIO (IO Int -> Int) -> IO Int -> Int
forall a b. (a -> b) -> a -> b
$
                ForeignPtr Word8 -> (Ptr Word8 -> IO Int) -> IO Int
forall a b. ForeignPtr a -> (Ptr a -> IO b) -> IO b
unsafeWithForeignPtr ForeignPtr Word8
fp0 ((Ptr Word8 -> IO Int) -> IO Int)
-> (Ptr Word8 -> IO Int) -> IO Int
forall a b. (a -> b) -> a -> b
$ \Ptr Word8
p0 ->
                ForeignPtr Word8 -> (Ptr Word8 -> IO Int) -> IO Int
forall a b. ForeignPtr a -> (Ptr a -> IO b) -> IO b
unsafeWithForeignPtr ForeignPtr Word8
fp1 ((Ptr Word8 -> IO Int) -> IO Int)
-> (Ptr Word8 -> IO Int) -> IO Int
forall a b. (a -> b) -> a -> b
$ \Ptr Word8
p1 ->
                Ptr Word8 -> Ptr Word8 -> Int -> IO Int
indexOfDifference
                    (Ptr Word8
p0 Ptr Word8 -> Int -> Ptr Word8
forall a. Storable a => Ptr a -> Int -> Ptr a
`ptrElemOff` Int
off0)
                    (Ptr Word8
p1 Ptr Word8 -> Int -> Ptr Word8
forall a. Storable a => Ptr a -> Int -> Ptr a
`ptrElemOff` Int
off1)
                    (Int
len0 Int -> Int -> Int
forall a. Ord a => a -> a -> a
`min` Int
len1)
        in  if Int
i Int -> Int -> Bool
forall a. Ord a => a -> a -> Bool
<= Int
0 -- can only be equal, but for paranoia's sake.
            then ByteString
-> ByteString -> ByteString -> (ByteString, ByteString, ByteString)
strictTriple ByteString
S.empty ByteString
s0 ByteString
s1
            else ByteString
-> ByteString -> ByteString -> (ByteString, ByteString, ByteString)
strictTriple
                    (if Int
off0 Int -> Int -> Int
forall a. Num a => a -> a -> a
+ Int
len0 Int -> Int -> Bool
forall a. Ord a => a -> a -> Bool
< Int
off1 Int -> Int -> Int
forall a. Num a => a -> a -> a
+ Int
len1  -- share the smaller one
                        then ForeignPtr Word8 -> Int -> Int -> ByteString
PS ForeignPtr Word8
fp0 Int
off0 Int
i  -- TODO: assert(i<=len0) for paranoia?
                        else ForeignPtr Word8 -> Int -> Int -> ByteString
PS ForeignPtr Word8
fp1 Int
off1 Int
i) -- TODO: assert(i<=len1) for paranoia?
                    (Int -> ForeignPtr Word8 -> Int -> Int -> ByteString
dropPS Int
i ForeignPtr Word8
fp0 Int
off0 Int
len0)
                    (Int -> ForeignPtr Word8 -> Int -> Int -> ByteString
dropPS Int
i ForeignPtr Word8
fp1 Int
off1 Int
len1)

-- | Construct a triple, strict in all arguments.  This helps improve
-- code generation over our previous approach.  Making our own
-- datatype for this result or CPSing 'breakMaximalPrefix' may still
-- improve things further.
strictTriple :: ByteString -> ByteString -> ByteString
             -> (ByteString,  ByteString,   ByteString)
strictTriple :: ByteString
-> ByteString -> ByteString -> (ByteString, ByteString, ByteString)
strictTriple !ByteString
p !ByteString
s !ByteString
z = (ByteString
p,ByteString
s,ByteString
z)
{-# INLINE strictTriple #-}

-- | Get the 'sizeOf' type @a@, without requiring @-XScopedTypeVariables@
-- nor making a spurious call to 'System.IO.Unsafe.unsafePerformIO' or similar.
sizeOfElem :: Storable a => Ptr a -> Int
sizeOfElem :: forall a. Storable a => Ptr a -> Int
sizeOfElem = a -> Int
forall a. Storable a => a -> Int
sizeOf (a -> Int) -> (Ptr a -> a) -> Ptr a -> Int
forall b c a. (b -> c) -> (a -> b) -> a -> c
. (Ptr a -> a
forall {a}. Ptr a -> a
forall a. HasCallStack => a
undefined :: Ptr a -> a)
{-# INLINE sizeOfElem #-}

-- | C-style pointer addition, without the excessively liberal type
-- of 'plusPtr'.
ptrElemOff :: Storable a => Ptr a -> Int -> Ptr a
ptrElemOff :: forall a. Storable a => Ptr a -> Int -> Ptr a
ptrElemOff Ptr a
p Int
i = Ptr a
p Ptr a -> Int -> Ptr a
forall a b. Ptr a -> Int -> Ptr b
`plusPtr` (Int
i Int -> Int -> Int
forall a. Num a => a -> a -> a
* Ptr a -> Int
forall a. Storable a => Ptr a -> Int
sizeOfElem Ptr a
p)
{-# INLINE [0] ptrElemOff #-}
-- This rewrite rule helps ensure that on bytestring>=0.11 we don't
-- incur any additional cost for using the 'PS' pattern synonym.
{-# RULES
"Data.Trie.ByteStringInternal ptrElemOff/0"
    forall p . ptrElemOff p 0 = p
 #-}

-- For bytestring>=0.11, there's no way to improve over the 'PS'
-- constructor synonym here.  After inlining, the @off=0@ from the
-- 'PS' pattern synonym will constant-propogate away, so all we'll
-- be left with is @BS (plusForeignPtr fp n) (len - n)@; which is
-- the same thing we would've written by hand.  Plus, bytestring>=0.11
-- will already define the compatibility definition of 'plusForeignPtr'
-- for use with base<4.10.
--
-- | Unpacked version of 'S.drop', for use as a smart-constructor.
-- N.B., this assumes the @n <= 0@ case has already been handled
-- (otherwise you might as well just say @drop n (PS fp off len)@
-- and let the compiler remove the intermediate 'PS').
dropPS :: Int -> ForeignPtr ByteStringElem -> Int -> Int -> ByteString
dropPS :: Int -> ForeignPtr Word8 -> Int -> Int -> ByteString
dropPS !Int
n !ForeignPtr Word8
fp !Int
off !Int
len
    | Int
n Int -> Int -> Bool
forall a. Ord a => a -> a -> Bool
>= Int
len  = ByteString
S.empty
    | Bool
otherwise = ForeignPtr Word8 -> Int -> Int -> ByteString
PS ForeignPtr Word8
fp (Int
off Int -> Int -> Int
forall a. Num a => a -> a -> a
+ Int
n) (Int
len Int -> Int -> Int
forall a. Num a => a -> a -> a
- Int
n)
{-# INLINE dropPS #-}


------------------------------------------------------------
-- This naive algorithm doesn't depend on architecture details.  We
-- could speed things up (in theory) by checking a natural word at
-- a time and then falling back to checking each byte once the
-- mismatched word is found.  But in practice that doesn't seem to
-- actually speed things up.
--
-- TODO: that's probably because of alignment issues, or because
-- we should really vectorize by the largest single load on an
-- architecture rather than by the natural word size.  For more
-- details on how to do it right, see GNU glibc's implementation
-- of @memcmp@.  We should be able to do a simple twist on that
-- algorithm to return the index of difference rather than the
-- ordering.  That would mean requiring GPL, but unfortunately every
-- other implementations of @memcmp@ I've found (FreeBSD libc, GCC's
-- builtin,...) just uses the same naive algorithm I have below.
-- I suppose we could always fork that algorithm off into a separate
-- optional dependency of this library; where we fallback to this
-- implementation if the user doesn't want the GPL burden.
--
-- | Calculates the first index where values differ.
indexOfDifference
    :: Ptr ByteStringElem
    -> Ptr ByteStringElem
    -> Int
    -> IO Int
indexOfDifference :: Ptr Word8 -> Ptr Word8 -> Int -> IO Int
indexOfDifference !Ptr Word8
p1 !Ptr Word8
p2 !Int
limit = Int -> IO Int
goByte Int
0
    where
    goByte :: Int -> IO Int
goByte Int
n
        | Int
n Int -> Int -> Bool
forall a. Ord a => a -> a -> Bool
>= Int
limit = Int -> IO Int
forall a. a -> IO a
forall (m :: * -> *) a. Monad m => a -> m a
return Int
limit
        | Bool
otherwise  = do
            Word8
c1 <- Ptr Word8 -> Int -> IO Word8
forall a. Storable a => Ptr a -> Int -> IO a
peekElemOff Ptr Word8
p1 Int
n
            Word8
c2 <- Ptr Word8 -> Int -> IO Word8
forall a. Storable a => Ptr a -> Int -> IO a
peekElemOff Ptr Word8
p2 Int
n
            if Word8
c1 Word8 -> Word8 -> Bool
forall a. Eq a => a -> a -> Bool
== Word8
c2
                then Int -> IO Int
goByte (Int
nInt -> Int -> Int
forall a. Num a => a -> a -> a
+Int
1)
                else Int -> IO Int
forall a. a -> IO a
forall (m :: * -> *) a. Monad m => a -> m a
return Int
n

-- TODO: why does bytestring-0.11 use 'peekByteOff' in lieu of
-- 'peekElemOff'?  Given the definitions, the latter is more
-- direct/simpler: using @readWord8OffAddr# p# n# s@ instead of
-- @readWord8OffAddr# (plusAddr# p# n# ) 0# s@, though surely GHC
-- will optimize those to generate the same assembly.

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

-- | A \"reversed\" variant of lazy bytestrings; i.e., a snoc-list
-- of strict bytestrings.
data RevLazyByteString
    = RevLazyByteString :+> {-# UNPACK #-} !S.ByteString
    -- Invariant: every 'S.ByteString' is non-null.
    | Nil

-- TODO: should we add an 'assert' even though we don't check in general?
-- | \(\mathcal{O}(1)\). Unsafely\/uncheckedly append a BS to the
-- RLBS.  It is up to the caller to maintain the invariant that
-- 'S.ByteString' is indeed non-null.
(+>!) :: RevLazyByteString -> S.ByteString -> RevLazyByteString
RevLazyByteString
xs +>! :: RevLazyByteString -> ByteString -> RevLazyByteString
+>! ByteString
x = RevLazyByteString
xs RevLazyByteString -> ByteString -> RevLazyByteString
:+> ByteString
x
{-# INLINE (+>!) #-}

-- | \(\mathcal{O}(1)\). Safely append a BS to the RLBS, maintaining
-- the invariant.
(+>?) :: RevLazyByteString -> S.ByteString -> RevLazyByteString
RevLazyByteString
xs +>? :: RevLazyByteString -> ByteString -> RevLazyByteString
+>? PS ForeignPtr Word8
_ Int
_ Int
0 = RevLazyByteString
xs
RevLazyByteString
xs +>? ByteString
x        = RevLazyByteString
xs RevLazyByteString -> ByteString -> RevLazyByteString
:+> ByteString
x
{-# INLINE (+>?) #-}

-- | \(\mathcal{O}(1)\). Safely convert a strict BS to RLBS,
-- maintaining the invariant.
fromStrict :: S.ByteString -> RevLazyByteString
fromStrict :: ByteString -> RevLazyByteString
fromStrict = (RevLazyByteString
Nil RevLazyByteString -> ByteString -> RevLazyByteString
+>?)
{-# INLINE fromStrict #-}

-- HACK: bytestring-0.10.8.1 (GHC 8.0.2) used 'S.checkedSum' (and
-- a simpler algorithm), whereas bytestring-0.10.8.2 (GHC 8.2.1)
-- introduced 'S.checkedAdd' instead; alas, those version numbers
-- cannot be differentiated by the MIN_VERSION_bytestring macro.
-- Thus, we'll simply define it ourselves.
-- TODO: since we built the trie from bytestrings that were short
-- enough to have a valid length, do we actually need to perform
-- this check at all?
--
-- | Add two non-negative numbers. Errors out on overflow.
(+?) :: Int -> Int -> Int
Int
x +? :: Int -> Int -> Int
+? Int
y
  | Int
r Int -> Int -> Bool
forall a. Ord a => a -> a -> Bool
>= Int
0    = Int
r
  | Bool
otherwise = [Char] -> Int
forall a. HasCallStack => [Char] -> a
error [Char]
overflowError
  where r :: Int
r = Int
x Int -> Int -> Int
forall a. Num a => a -> a -> a
+ Int
y
{-# INLINE (+?) #-}

overflowError :: String
overflowError :: [Char]
overflowError = [Char]
"Data.Trie.ByteStringInternal.toStrict: size overflow"
{-# NOINLINE overflowError #-}

-- See commentary at LazyByteString's version of @toStrict@.  This
-- implementation is from Git SHA 688f3c0887f2ca0623f2f54f78e8f675f92e31bf,
-- modulo the necessary changes for using a snoc-list in lieu of a
-- cons-list.
-- | \(\mathcal{O}(n)\). Convert the RLBS to a strict BS, by copying it.
toStrict :: RevLazyByteString -> S.ByteString
toStrict :: RevLazyByteString -> ByteString
toStrict = \RevLazyByteString
cs0 -> RevLazyByteString -> RevLazyByteString -> ByteString
goLen0 RevLazyByteString
cs0 RevLazyByteString
cs0
    where
    -- It's still possible that the result is empty.
    goLen0 :: RevLazyByteString -> RevLazyByteString -> ByteString
goLen0 RevLazyByteString
_               RevLazyByteString
Nil                = ByteString
S.empty
    goLen0 RevLazyByteString
cs0             (RevLazyByteString
cs :+> PS ForeignPtr Word8
_ Int
_ Int
0)  = RevLazyByteString -> RevLazyByteString -> ByteString
goLen0 RevLazyByteString
cs0 RevLazyByteString
cs
    goLen0 RevLazyByteString
cs0             (RevLazyByteString
cs :+> ByteString
c)         = RevLazyByteString -> ByteString -> RevLazyByteString -> ByteString
goLen1 RevLazyByteString
cs0 ByteString
c RevLazyByteString
cs
    -- It's still possible that the result is a single chunk.
    goLen1 :: RevLazyByteString -> ByteString -> RevLazyByteString -> ByteString
goLen1 RevLazyByteString
_   ByteString
b           RevLazyByteString
Nil                = ByteString
b
    goLen1 RevLazyByteString
cs0 ByteString
b           (RevLazyByteString
cs :+> PS ForeignPtr Word8
_ Int
_ Int
0)  = RevLazyByteString -> ByteString -> RevLazyByteString -> ByteString
goLen1 RevLazyByteString
cs0 ByteString
b RevLazyByteString
cs
    goLen1 RevLazyByteString
cs0 (PS ForeignPtr Word8
_ Int
_ Int
bl) (RevLazyByteString
cs :+> PS ForeignPtr Word8
_ Int
_ Int
cl) = RevLazyByteString -> Int -> RevLazyByteString -> ByteString
goLen  RevLazyByteString
cs0 (Int
bl Int -> Int -> Int
+? Int
cl) RevLazyByteString
cs
    -- General case, just find the total length we'll need.
    goLen :: RevLazyByteString -> Int -> RevLazyByteString -> ByteString
goLen  RevLazyByteString
cs0 !Int
total      (RevLazyByteString
cs :+> PS ForeignPtr Word8
_ Int
_ Int
cl) = RevLazyByteString -> Int -> RevLazyByteString -> ByteString
goLen  RevLazyByteString
cs0 (Int
total Int -> Int -> Int
+? Int
cl) RevLazyByteString
cs
    goLen  RevLazyByteString
cs0  Int
total      RevLazyByteString
Nil                =
        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 ->
            -- TODO: this gives the correct behavior (re off-by-one
            -- concerns); however, it is bad praxis to use a pointer
            -- to something outside the allocated region; even if
            -- it is just pointing to the first invalid byte after
            -- the allocated region.
            RevLazyByteString -> Ptr Word8 -> IO ()
goCopy RevLazyByteString
cs0 (Ptr Word8
ptr Ptr Word8 -> Int -> Ptr Word8
forall a. Storable a => Ptr a -> Int -> Ptr a
`ptrElemOff` Int
total)
    -- Copy the data
    goCopy :: RevLazyByteString -> Ptr Word8 -> IO ()
goCopy RevLazyByteString
Nil                    !Ptr Word8
_   = () -> IO ()
forall a. a -> IO a
forall (m :: * -> *) a. Monad m => a -> m a
return ()
    goCopy (RevLazyByteString
cs :+> PS ForeignPtr Word8
_  Int
_   Int
0  ) !Ptr Word8
ptr = RevLazyByteString -> Ptr Word8 -> IO ()
goCopy RevLazyByteString
cs Ptr Word8
ptr
    goCopy (RevLazyByteString
cs :+> PS ForeignPtr Word8
fp Int
off Int
len) !Ptr Word8
ptr =
        ForeignPtr Word8 -> (Ptr Word8 -> IO ()) -> IO ()
forall a b. ForeignPtr a -> (Ptr a -> IO b) -> IO b
unsafeWithForeignPtr ForeignPtr Word8
fp ((Ptr Word8 -> IO ()) -> IO ()) -> (Ptr Word8 -> IO ()) -> IO ()
forall a b. (a -> b) -> a -> b
$ \Ptr Word8
p -> do
            let ptr' :: Ptr Word8
ptr' = Ptr Word8
ptr Ptr Word8 -> Int -> Ptr Word8
forall a. Storable a => Ptr a -> Int -> Ptr a
`ptrElemOff` Int -> Int
forall a. Num a => a -> a
negate Int
len
            Ptr Word8 -> Ptr Word8 -> Int -> IO ()
S.memcpy Ptr Word8
ptr' (Ptr Word8
p Ptr Word8 -> Int -> Ptr Word8
forall a. Storable a => Ptr a -> Int -> Ptr a
`ptrElemOff` Int
off) Int
len
            RevLazyByteString -> Ptr Word8 -> IO ()
goCopy RevLazyByteString
cs Ptr Word8
ptr'

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