{-# LANGUAGE CPP #-}
{-# LANGUAGE MagicHash #-}
{-# LANGUAGE RankNTypes #-}
{-# LANGUAGE UnboxedTuples #-}
{-# LANGUAGE BangPatterns #-}
{-# LANGUAGE ViewPatterns #-}
{-# LANGUAGE UnliftedFFITypes         #-}

-- |
-- Module      :  System.OsPath.Data.ByteString.Short.Internal
-- Copyright   :  © 2022 Julian Ospald
-- License     :  MIT
--
-- Maintainer  :  Julian Ospald <hasufell@posteo.de>
-- Stability   :  experimental
-- Portability :  portable
--
-- Internal low-level utilities mostly for 'System.OsPath.Data.ByteString.Short.Word16',
-- such as byte-array operations and other stuff not meant to be exported from Word16 module.
module System.OsPath.Data.ByteString.Short.Internal where

import Control.Monad.ST
import Control.Exception (assert, throwIO)
import Data.Bits (Bits(..))
import Data.ByteString.Short.Internal (ShortByteString(..), length)
#if !MIN_VERSION_base(4,11,0)
import Data.Semigroup
  ( Semigroup((<>)) )
import Foreign.C.Types
  ( CSize(..)
  , CInt(..)
  )
import Data.ByteString.Internal
  ( accursedUnutterablePerformIO
  )
#endif
#if !MIN_VERSION_bytestring(0,10,9)
import Foreign.Marshal.Alloc (allocaBytes)
import Foreign.C.String ( CString, CStringLen )
import Foreign.C.Types ( CSize(..) )
import Foreign.Storable (pokeByteOff)
#endif
import Foreign.Marshal.Array (withArray0, peekArray0, newArray0, withArrayLen, peekArray)
import GHC.Exts
import GHC.Word
import GHC.ST
    ( ST (ST) )
import GHC.Stack ( HasCallStack )
import Prelude hiding
    ( length )

import qualified Data.ByteString.Short.Internal as BS
import qualified Data.Char as C
import qualified Data.List as List


_nul :: Word16
_nul :: Word16
_nul = Word16
0x00

isSpace :: Word16 -> Bool
isSpace :: Word16 -> Bool
isSpace = Char -> Bool
C.isSpace forall b c a. (b -> c) -> (a -> b) -> a -> c
. Word16 -> Char
word16ToChar

-- | Total conversion to char.
word16ToChar :: Word16 -> Char
word16ToChar :: Word16 -> Char
word16ToChar = Int -> Char
C.chr forall b c a. (b -> c) -> (a -> b) -> a -> c
. forall a b. (Integral a, Num b) => a -> b
fromIntegral

create :: Int -> (forall s. MBA s -> ST s ()) -> ShortByteString
create :: Int -> (forall s. MBA s -> ST s ()) -> ShortByteString
create Int
len forall s. MBA s -> ST s ()
fill =
    forall a. (forall s. ST s a) -> a
runST forall a b. (a -> b) -> a -> b
$ do
      MBA s
mba <- forall s. Int -> ST s (MBA s)
newByteArray Int
len
      forall s. MBA s -> ST s ()
fill MBA s
mba
      BA# ByteArray#
ba# <- forall s. MBA s -> ST s BA
unsafeFreezeByteArray MBA s
mba
      forall (m :: * -> *) a. Monad m => a -> m a
return (ByteArray# -> ShortByteString
SBS ByteArray#
ba#)
{-# INLINE create #-}


asBA :: ShortByteString -> BA
asBA :: ShortByteString -> BA
asBA (SBS ByteArray#
ba#) = ByteArray# -> BA
BA# ByteArray#
ba#



data BA    = BA# ByteArray#
data MBA s = MBA# (MutableByteArray# s)


newPinnedByteArray :: Int -> ST s (MBA s)
newPinnedByteArray :: forall s. Int -> ST s (MBA s)
newPinnedByteArray (I# Int#
len#) =
    forall s a. STRep s a -> ST s a
ST forall a b. (a -> b) -> a -> b
$ \State# s
s -> case forall d. Int# -> State# d -> (# State# d, MutableByteArray# d #)
newPinnedByteArray# Int#
len# State# s
s of
                 (# State# s
s', MutableByteArray# s
mba# #) -> (# State# s
s', forall s. MutableByteArray# s -> MBA s
MBA# MutableByteArray# s
mba# #)

newByteArray :: Int -> ST s (MBA s)
newByteArray :: forall s. Int -> ST s (MBA s)
newByteArray (I# Int#
len#) =
    forall s a. STRep s a -> ST s a
ST forall a b. (a -> b) -> a -> b
$ \State# s
s -> case forall d. Int# -> State# d -> (# State# d, MutableByteArray# d #)
newByteArray# Int#
len# State# s
s of
                 (# State# s
s', MutableByteArray# s
mba# #) -> (# State# s
s', forall s. MutableByteArray# s -> MBA s
MBA# MutableByteArray# s
mba# #)

copyByteArray :: BA -> Int -> MBA s -> Int -> Int -> ST s ()
copyByteArray :: forall s. BA -> Int -> MBA s -> Int -> Int -> ST s ()
copyByteArray (BA# ByteArray#
src#) (I# Int#
src_off#) (MBA# MutableByteArray# s
dst#) (I# Int#
dst_off#) (I# Int#
len#) =
    forall s a. STRep s a -> ST s a
ST forall a b. (a -> b) -> a -> b
$ \State# s
s -> case forall d.
ByteArray#
-> Int#
-> MutableByteArray# d
-> Int#
-> Int#
-> State# d
-> State# d
copyByteArray# ByteArray#
src# Int#
src_off# MutableByteArray# s
dst# Int#
dst_off# Int#
len# State# s
s of
                 State# s
s' -> (# State# s
s', () #)

unsafeFreezeByteArray :: MBA s -> ST s BA
unsafeFreezeByteArray :: forall s. MBA s -> ST s BA
unsafeFreezeByteArray (MBA# MutableByteArray# s
mba#) =
    forall s a. STRep s a -> ST s a
ST forall a b. (a -> b) -> a -> b
$ \State# s
s -> case forall d.
MutableByteArray# d -> State# d -> (# State# d, ByteArray# #)
unsafeFreezeByteArray# MutableByteArray# s
mba# State# s
s of
                 (# State# s
s', ByteArray#
ba# #) -> (# State# s
s', ByteArray# -> BA
BA# ByteArray#
ba# #)

copyAddrToByteArray :: Ptr a -> MBA RealWorld -> Int -> Int -> ST RealWorld ()
copyAddrToByteArray :: forall a. Ptr a -> MBA RealWorld -> Int -> Int -> ST RealWorld ()
copyAddrToByteArray (Ptr Addr#
src#) (MBA# MutableByteArray# RealWorld
dst#) (I# Int#
dst_off#) (I# Int#
len#) =
    forall s a. STRep s a -> ST s a
ST forall a b. (a -> b) -> a -> b
$ \State# RealWorld
s -> case forall d.
Addr#
-> MutableByteArray# d -> Int# -> Int# -> State# d -> State# d
copyAddrToByteArray# Addr#
src# MutableByteArray# RealWorld
dst# Int#
dst_off# Int#
len# State# RealWorld
s of
                 State# RealWorld
s' -> (# State# RealWorld
s', () #)


-- this is a copy-paste from bytestring
#if !MIN_VERSION_bytestring(0,10,9)
------------------------------------------------------------------------
-- Primop replacements

-- ---------------------------------------------------------------------
--
-- Standard C functions
--

foreign import ccall unsafe "string.h strlen" c_strlen
    :: CString -> IO CSize


-- ---------------------------------------------------------------------
--
-- Uses our C code
--

-- | /O(n)./ Construct a new @ShortByteString@ from a @CString@. The
-- resulting @ShortByteString@ is an immutable copy of the original
-- @CString@, and is managed on the Haskell heap. The original
-- @CString@ must be null terminated.
--
-- @since 0.10.10.0
packCString :: CString -> IO ShortByteString
packCString cstr = do
  len <- c_strlen cstr
  packCStringLen (cstr, fromIntegral len)

-- | /O(n)./ Construct a new @ShortByteString@ from a @CStringLen@. The
-- resulting @ShortByteString@ is an immutable copy of the original @CStringLen@.
-- The @ShortByteString@ is a normal Haskell value and will be managed on the
-- Haskell heap.
--
-- @since 0.10.10.0
packCStringLen :: CStringLen -> IO ShortByteString
packCStringLen (cstr, len) | len >= 0 = BS.createFromPtr cstr len
packCStringLen (_, len) =
  moduleErrorIO "packCStringLen" ("negative length: " ++ show len)

-- | /O(n) construction./ Use a @ShortByteString@ with a function requiring a
-- null-terminated @CString@.  The @CString@ is a copy and will be freed
-- automatically; it must not be stored or used after the
-- subcomputation finishes.
--
-- @since 0.10.10.0
useAsCString :: ShortByteString -> (CString -> IO a) -> IO a
useAsCString bs action =
  allocaBytes (l+1) $ \buf -> do
      BS.copyToPtr bs 0 buf (fromIntegral l)
      pokeByteOff buf l (0::Word8)
      action buf
  where l = length bs

-- | /O(n) construction./ Use a @ShortByteString@ with a function requiring a @CStringLen@.
-- As for @useAsCString@ this function makes a copy of the original @ShortByteString@.
-- It must not be stored or used after the subcomputation finishes.
--
-- @since 0.10.10.0
useAsCStringLen :: ShortByteString -> (CStringLen -> IO a) -> IO a
useAsCStringLen bs action =
  allocaBytes l $ \buf -> do
      BS.copyToPtr bs 0 buf (fromIntegral l)
      action (buf, l)
  where l = length bs


#endif


-- | /O(n)./ Construct a new @ShortByteString@ from a @CWString@. The
-- resulting @ShortByteString@ is an immutable copy of the original
-- @CWString@, and is managed on the Haskell heap. The original
-- @CWString@ must be null terminated.
--
-- @since 0.10.10.0
packCWString :: Ptr Word16 -> IO ShortByteString
packCWString :: Ptr Word16 -> IO ShortByteString
packCWString Ptr Word16
cwstr = do
  [Word16]
cs <- forall a. (Storable a, Eq a) => a -> Ptr a -> IO [a]
peekArray0 Word16
_nul Ptr Word16
cwstr
  forall (m :: * -> *) a. Monad m => a -> m a
return ([Word16] -> ShortByteString
packWord16 [Word16]
cs)

-- | /O(n)./ Construct a new @ShortByteString@ from a @CWStringLen@. The
-- resulting @ShortByteString@ is an immutable copy of the original @CWStringLen@.
-- The @ShortByteString@ is a normal Haskell value and will be managed on the
-- Haskell heap.
--
-- @since 0.10.10.0
packCWStringLen :: (Ptr Word16, Int) -> IO ShortByteString
packCWStringLen :: (Ptr Word16, Int) -> IO ShortByteString
packCWStringLen (Ptr Word16
cp, Int
len) = do
  [Word16]
cs <- forall a. Storable a => Int -> Ptr a -> IO [a]
peekArray Int
len Ptr Word16
cp
  forall (m :: * -> *) a. Monad m => a -> m a
return ([Word16] -> ShortByteString
packWord16 [Word16]
cs)


-- | /O(n) construction./ Use a @ShortByteString@ with a function requiring a
-- null-terminated @CWString@.  The @CWString@ is a copy and will be freed
-- automatically; it must not be stored or used after the
-- subcomputation finishes.
--
-- @since 0.10.10.0
useAsCWString :: ShortByteString -> (Ptr Word16 -> IO a) -> IO a
useAsCWString :: forall a. ShortByteString -> (Ptr Word16 -> IO a) -> IO a
useAsCWString = forall a b. Storable a => a -> [a] -> (Ptr a -> IO b) -> IO b
withArray0 Word16
_nul forall b c a. (b -> c) -> (a -> b) -> a -> c
. ShortByteString -> [Word16]
unpackWord16

-- | /O(n) construction./ Use a @ShortByteString@ with a function requiring a @CWStringLen@.
-- As for @useAsCWString@ this function makes a copy of the original @ShortByteString@.
-- It must not be stored or used after the subcomputation finishes.
--
-- @since 0.10.10.0
useAsCWStringLen :: ShortByteString -> ((Ptr Word16, Int) -> IO a) -> IO a
useAsCWStringLen :: forall a. ShortByteString -> ((Ptr Word16, Int) -> IO a) -> IO a
useAsCWStringLen ShortByteString
bs (Ptr Word16, Int) -> IO a
action = forall a b. Storable a => [a] -> (Int -> Ptr a -> IO b) -> IO b
withArrayLen (ShortByteString -> [Word16]
unpackWord16 ShortByteString
bs) forall a b. (a -> b) -> a -> b
$ \ Int
len Ptr Word16
ptr -> (Ptr Word16, Int) -> IO a
action (Ptr Word16
ptr, Int
len)

-- | /O(n) construction./ Use a @ShortByteString@ with a function requiring a @CWStringLen@.
-- As for @useAsCWString@ this function makes a copy of the original @ShortByteString@.
-- It must not be stored or used after the subcomputation finishes.
--
-- @since 0.10.10.0
newCWString :: ShortByteString -> IO (Ptr Word16)
newCWString :: ShortByteString -> IO (Ptr Word16)
newCWString = forall a. Storable a => a -> [a] -> IO (Ptr a)
newArray0 Word16
_nul forall b c a. (b -> c) -> (a -> b) -> a -> c
. ShortByteString -> [Word16]
unpackWord16




 -- ---------------------------------------------------------------------
-- Internal utilities

moduleErrorIO :: String -> String -> IO a
moduleErrorIO :: forall a. [Char] -> [Char] -> IO a
moduleErrorIO [Char]
fun [Char]
msg = forall e a. Exception e => e -> IO a
throwIO forall b c a. (b -> c) -> (a -> b) -> a -> c
. [Char] -> IOError
userError forall a b. (a -> b) -> a -> b
$ [Char] -> [Char] -> [Char]
moduleErrorMsg [Char]
fun [Char]
msg
{-# NOINLINE moduleErrorIO #-}

moduleErrorMsg :: String -> String -> String
moduleErrorMsg :: [Char] -> [Char] -> [Char]
moduleErrorMsg [Char]
fun [Char]
msg = [Char]
"System.OsPath.Data.ByteString.Short." forall a. [a] -> [a] -> [a]
++ [Char]
fun forall a. [a] -> [a] -> [a]
++ Char
':'forall a. a -> [a] -> [a]
:Char
' 'forall a. a -> [a] -> [a]
:[Char]
msg

packWord16 :: [Word16] -> ShortByteString
packWord16 :: [Word16] -> ShortByteString
packWord16 [Word16]
cs = Int -> [Word16] -> ShortByteString
packLenWord16 (forall (t :: * -> *) a. Foldable t => t a -> Int
List.length [Word16]
cs) [Word16]
cs

packLenWord16 :: Int -> [Word16] -> ShortByteString
packLenWord16 :: Int -> [Word16] -> ShortByteString
packLenWord16 Int
len [Word16]
ws0 =
    Int -> (forall s. MBA s -> ST s ()) -> ShortByteString
create (Int
len forall a. Num a => a -> a -> a
* Int
2) (\MBA s
mba -> forall s. MBA s -> Int -> [Word16] -> ST s ()
go MBA s
mba Int
0 [Word16]
ws0)
  where
    go :: MBA s -> Int -> [Word16] -> ST s ()
    go :: forall s. MBA s -> Int -> [Word16] -> ST s ()
go !MBA s
_   !Int
_ []     = forall (m :: * -> *) a. Monad m => a -> m a
return ()
    go !MBA s
mba !Int
i (Word16
w:[Word16]
ws) = do
      forall s. MBA s -> Int -> Word16 -> ST s ()
writeWord16Array MBA s
mba Int
i Word16
w
      forall s. MBA s -> Int -> [Word16] -> ST s ()
go MBA s
mba (Int
iforall a. Num a => a -> a -> a
+Int
2) [Word16]
ws


unpackWord16 :: ShortByteString -> [Word16]
unpackWord16 :: ShortByteString -> [Word16]
unpackWord16 ShortByteString
sbs = Int -> [Word16] -> [Word16]
go Int
len []
  where
    len :: Int
len = ShortByteString -> Int
length ShortByteString
sbs
    go :: Int -> [Word16] -> [Word16]
go !Int
i ![Word16]
acc
      | Int
i forall a. Ord a => a -> a -> Bool
< Int
1     = [Word16]
acc
      | Bool
otherwise = let !w :: Word16
w = BA -> Int -> Word16
indexWord16Array (ShortByteString -> BA
asBA ShortByteString
sbs) (Int
i forall a. Num a => a -> a -> a
- Int
2)
                    in Int -> [Word16] -> [Word16]
go (Int
i forall a. Num a => a -> a -> a
- Int
2) (Word16
wforall a. a -> [a] -> [a]
:[Word16]
acc)

packWord16Rev :: [Word16] -> ShortByteString
packWord16Rev :: [Word16] -> ShortByteString
packWord16Rev [Word16]
cs = Int -> [Word16] -> ShortByteString
packLenWord16Rev (forall (t :: * -> *) a. Foldable t => t a -> Int
List.length [Word16]
cs forall a. Num a => a -> a -> a
* Int
2) [Word16]
cs

packLenWord16Rev :: Int -> [Word16] -> ShortByteString
packLenWord16Rev :: Int -> [Word16] -> ShortByteString
packLenWord16Rev Int
len [Word16]
ws0 =
    Int -> (forall s. MBA s -> ST s ()) -> ShortByteString
create Int
len (\MBA s
mba -> forall s. MBA s -> Int -> [Word16] -> ST s ()
go MBA s
mba Int
len [Word16]
ws0)
  where
    go :: MBA s -> Int -> [Word16] -> ST s ()
    go :: forall s. MBA s -> Int -> [Word16] -> ST s ()
go !MBA s
_   !Int
_ []     = forall (m :: * -> *) a. Monad m => a -> m a
return ()
    go !MBA s
mba !Int
i (Word16
w:[Word16]
ws) = do
      forall s. MBA s -> Int -> Word16 -> ST s ()
writeWord16Array MBA s
mba (Int
i forall a. Num a => a -> a -> a
- Int
2) Word16
w
      forall s. MBA s -> Int -> [Word16] -> ST s ()
go MBA s
mba (Int
i forall a. Num a => a -> a -> a
- Int
2) [Word16]
ws


-- | This isn't strictly Word16 array write. Instead it's two consecutive Word8 array
-- writes to avoid endianness issues due to primops doing automatic alignment based
-- on host platform. We want to always write LE to the byte array.
writeWord16Array :: MBA s
                 -> Int      -- ^ Word8 index (not Word16)
                 -> Word16
                 -> ST s ()
writeWord16Array :: forall s. MBA s -> Int -> Word16 -> ST s ()
writeWord16Array (MBA# MutableByteArray# s
mba#) (I# Int#
i#) (W16# Word16#
w#) =
  case Word16# -> (# Word8#, Word8# #)
encodeWord16LE# Word16#
w# of
    (# Word8#
lsb#, Word8#
msb# #) ->
      forall s a. STRep s a -> ST s a
ST (\State# s
s -> case forall d.
MutableByteArray# d -> Int# -> Word8# -> State# d -> State# d
writeWord8Array# MutableByteArray# s
mba# Int#
i# Word8#
lsb# State# s
s of
          State# s
s' -> (# State# s
s', () #)) forall (m :: * -> *) a b. Monad m => m a -> m b -> m b
>>
      forall s a. STRep s a -> ST s a
ST (\State# s
s -> case forall d.
MutableByteArray# d -> Int# -> Word8# -> State# d -> State# d
writeWord8Array# MutableByteArray# s
mba# (Int#
i# Int# -> Int# -> Int#
+# Int#
1#) Word8#
msb# State# s
s of
          State# s
s' -> (# State# s
s', () #))

indexWord8Array :: BA
                -> Int      -- ^ Word8 index
                -> Word8
indexWord8Array :: BA -> Int -> Word8
indexWord8Array (BA# ByteArray#
ba#) (I# Int#
i#) = Word8# -> Word8
W8# (ByteArray# -> Int# -> Word8#
indexWord8Array# ByteArray#
ba# Int#
i#)

-- | This isn't strictly Word16 array read. Instead it's two Word8 array reads
-- to avoid endianness issues due to primops doing automatic alignment based
-- on host platform. We expect the byte array to be LE always.
indexWord16Array :: BA
                 -> Int      -- ^ Word8 index (not Word16)
                 -> Word16
indexWord16Array :: BA -> Int -> Word16
indexWord16Array BA
ba Int
i = forall a b. (Integral a, Num b) => a -> b
fromIntegral Word8
lsb forall a. Bits a => a -> a -> a
.|. (forall a b. (Integral a, Num b) => a -> b
fromIntegral Word8
msb forall a. Bits a => a -> Int -> a
`shiftL` Int
8)
  where
    lsb :: Word8
lsb = BA -> Int -> Word8
indexWord8Array BA
ba Int
i
    msb :: Word8
msb = BA -> Int -> Word8
indexWord8Array BA
ba (Int
i forall a. Num a => a -> a -> a
+ Int
1)

#if !MIN_VERSION_base(4,16,0)

encodeWord16LE# :: Word#              -- ^ Word16
                -> (# Word#, Word# #) -- ^ Word8 (LSB, MSB)
encodeWord16LE# x# = (# x# `and#` int2Word# 0xff#
                     ,  x# `and#` int2Word# 0xff00# `shiftRL#` 8# #)

decodeWord16LE# :: (# Word#, Word# #) -- ^ Word8 (LSB, MSB)
                -> Word#              -- ^ Word16
decodeWord16LE# (# lsb#, msb# #) = msb# `shiftL#` 8# `or#` lsb#

#else

encodeWord16LE# :: Word16#              -- ^ Word16
                -> (# Word8#, Word8# #) -- ^ Word8 (LSB, MSB)
encodeWord16LE# :: Word16# -> (# Word8#, Word8# #)
encodeWord16LE# Word16#
x# = (# Word16# -> Word8#
word16ToWord8# Word16#
x#
                     ,  Word16# -> Word8#
word16ToWord8# (Word16#
x# Word16# -> Int# -> Word16#
`uncheckedShiftRLWord16#` Int#
8#) #)
  where
    word16ToWord8# :: Word16# -> Word8#
word16ToWord8# Word16#
y = Word# -> Word8#
wordToWord8# (Word16# -> Word#
word16ToWord# Word16#
y)

decodeWord16LE# :: (# Word8#, Word8# #) -- ^ Word8 (LSB, MSB)
                -> Word16#              -- ^ Word16
decodeWord16LE# :: (# Word8#, Word8# #) -> Word16#
decodeWord16LE# (# Word8#
lsb#, Word8#
msb# #) = ((Word8# -> Word16#
word8ToWord16# Word8#
msb# Word16# -> Int# -> Word16#
`uncheckedShiftLWord16#` Int#
8#) Word16# -> Word16# -> Word16#
`orWord16#` Word8# -> Word16#
word8ToWord16# Word8#
lsb#)
  where
    word8ToWord16# :: Word8# -> Word16#
word8ToWord16# Word8#
y = Word# -> Word16#
wordToWord16# (Word8# -> Word#
word8ToWord# Word8#
y)

#endif

setByteArray :: MBA s -> Int -> Int -> Int -> ST s ()
setByteArray :: forall s. MBA s -> Int -> Int -> Int -> ST s ()
setByteArray (MBA# MutableByteArray# s
dst#) (I# Int#
off#) (I# Int#
len#) (I# Int#
c#) =
    forall s a. STRep s a -> ST s a
ST forall a b. (a -> b) -> a -> b
$ \State# s
s -> case forall d.
MutableByteArray# d -> Int# -> Int# -> Int# -> State# d -> State# d
setByteArray# MutableByteArray# s
dst# Int#
off# Int#
len# Int#
c# State# s
s of
                 State# s
s' -> (# State# s
s', () #)

copyMutableByteArray :: MBA s -> Int -> MBA s -> Int -> Int -> ST s ()
copyMutableByteArray :: forall s. MBA s -> Int -> MBA s -> Int -> Int -> ST s ()
copyMutableByteArray (MBA# MutableByteArray# s
src#) (I# Int#
src_off#) (MBA# MutableByteArray# s
dst#) (I# Int#
dst_off#) (I# Int#
len#) =
    forall s a. STRep s a -> ST s a
ST forall a b. (a -> b) -> a -> b
$ \State# s
s -> case forall d.
MutableByteArray# d
-> Int#
-> MutableByteArray# d
-> Int#
-> Int#
-> State# d
-> State# d
copyMutableByteArray# MutableByteArray# s
src# Int#
src_off# MutableByteArray# s
dst# Int#
dst_off# Int#
len# State# s
s of
                 State# s
s' -> (# State# s
s', () #)

-- | Given the maximum size needed and a function to make the contents
-- of a ShortByteString, createAndTrim makes the 'ShortByteString'.
-- The generating function is required to return the actual final size
-- (<= the maximum size) and the result value. The resulting byte array
-- is realloced to this size.
createAndTrim :: Int -> (forall s. MBA s -> ST s (Int, a)) -> (ShortByteString, a)
createAndTrim :: forall a.
Int -> (forall s. MBA s -> ST s (Int, a)) -> (ShortByteString, a)
createAndTrim Int
l forall s. MBA s -> ST s (Int, a)
fill =
    forall a. (forall s. ST s a) -> a
runST forall a b. (a -> b) -> a -> b
$ do
      MBA s
mba <- forall s. Int -> ST s (MBA s)
newByteArray Int
l
      (Int
l', a
res) <- forall s. MBA s -> ST s (Int, a)
fill MBA s
mba
      if forall a. HasCallStack => Bool -> a -> a
assert (Int
l' forall a. Ord a => a -> a -> Bool
<= Int
l) forall a b. (a -> b) -> a -> b
$ Int
l' forall a. Ord a => a -> a -> Bool
>= Int
l
          then do
            BA# ByteArray#
ba# <- forall s. MBA s -> ST s BA
unsafeFreezeByteArray MBA s
mba
            forall (m :: * -> *) a. Monad m => a -> m a
return (ByteArray# -> ShortByteString
SBS ByteArray#
ba#, a
res)
          else do
            MBA s
mba2 <- forall s. Int -> ST s (MBA s)
newByteArray Int
l'
            forall s. MBA s -> Int -> MBA s -> Int -> Int -> ST s ()
copyMutableByteArray MBA s
mba Int
0 MBA s
mba2 Int
0 Int
l'
            BA# ByteArray#
ba# <- forall s. MBA s -> ST s BA
unsafeFreezeByteArray MBA s
mba2
            forall (m :: * -> *) a. Monad m => a -> m a
return (ByteArray# -> ShortByteString
SBS ByteArray#
ba#, a
res)
{-# INLINE createAndTrim #-}

createAndTrim' :: Int -> (forall s. MBA s -> ST s Int) -> ShortByteString
createAndTrim' :: Int -> (forall s. MBA s -> ST s Int) -> ShortByteString
createAndTrim' Int
l forall s. MBA s -> ST s Int
fill =
    forall a. (forall s. ST s a) -> a
runST forall a b. (a -> b) -> a -> b
$ do
      MBA s
mba <- forall s. Int -> ST s (MBA s)
newByteArray Int
l
      Int
l' <- forall s. MBA s -> ST s Int
fill MBA s
mba
      if forall a. HasCallStack => Bool -> a -> a
assert (Int
l' forall a. Ord a => a -> a -> Bool
<= Int
l) forall a b. (a -> b) -> a -> b
$ Int
l' forall a. Ord a => a -> a -> Bool
>= Int
l
          then do
            BA# ByteArray#
ba# <- forall s. MBA s -> ST s BA
unsafeFreezeByteArray MBA s
mba
            forall (m :: * -> *) a. Monad m => a -> m a
return (ByteArray# -> ShortByteString
SBS ByteArray#
ba#)
          else do
            MBA s
mba2 <- forall s. Int -> ST s (MBA s)
newByteArray Int
l'
            forall s. MBA s -> Int -> MBA s -> Int -> Int -> ST s ()
copyMutableByteArray MBA s
mba Int
0 MBA s
mba2 Int
0 Int
l'
            BA# ByteArray#
ba# <- forall s. MBA s -> ST s BA
unsafeFreezeByteArray MBA s
mba2
            forall (m :: * -> *) a. Monad m => a -> m a
return (ByteArray# -> ShortByteString
SBS ByteArray#
ba#)
{-# INLINE createAndTrim' #-}

createAndTrim'' :: Int -> (forall s. MBA s -> MBA s -> ST s (Int, Int)) -> (ShortByteString, ShortByteString)
createAndTrim'' :: Int
-> (forall s. MBA s -> MBA s -> ST s (Int, Int))
-> (ShortByteString, ShortByteString)
createAndTrim'' Int
l forall s. MBA s -> MBA s -> ST s (Int, Int)
fill =
    forall a. (forall s. ST s a) -> a
runST forall a b. (a -> b) -> a -> b
$ do
      MBA s
mba1 <- forall s. Int -> ST s (MBA s)
newByteArray Int
l
      MBA s
mba2 <- forall s. Int -> ST s (MBA s)
newByteArray Int
l
      (Int
l1, Int
l2) <- forall s. MBA s -> MBA s -> ST s (Int, Int)
fill MBA s
mba1 MBA s
mba2
      ShortByteString
sbs1 <- forall s. Int -> MBA s -> ST s ShortByteString
freeze' Int
l1 MBA s
mba1
      ShortByteString
sbs2 <- forall s. Int -> MBA s -> ST s ShortByteString
freeze' Int
l2 MBA s
mba2
      forall (f :: * -> *) a. Applicative f => a -> f a
pure (ShortByteString
sbs1, ShortByteString
sbs2)
  where
    freeze' :: Int -> MBA s -> ST s ShortByteString
    freeze' :: forall s. Int -> MBA s -> ST s ShortByteString
freeze' Int
l' MBA s
mba =
      if forall a. HasCallStack => Bool -> a -> a
assert (Int
l' forall a. Ord a => a -> a -> Bool
<= Int
l) forall a b. (a -> b) -> a -> b
$ Int
l' forall a. Ord a => a -> a -> Bool
>= Int
l
          then do
            BA# ByteArray#
ba# <- forall s. MBA s -> ST s BA
unsafeFreezeByteArray MBA s
mba
            forall (m :: * -> *) a. Monad m => a -> m a
return (ByteArray# -> ShortByteString
SBS ByteArray#
ba#)
          else do
            MBA s
mba2 <- forall s. Int -> ST s (MBA s)
newByteArray Int
l'
            forall s. MBA s -> Int -> MBA s -> Int -> Int -> ST s ()
copyMutableByteArray MBA s
mba Int
0 MBA s
mba2 Int
0 Int
l'
            BA# ByteArray#
ba# <- forall s. MBA s -> ST s BA
unsafeFreezeByteArray MBA s
mba2
            forall (m :: * -> *) a. Monad m => a -> m a
return (ByteArray# -> ShortByteString
SBS ByteArray#
ba#)
{-# INLINE createAndTrim'' #-}

-- Returns the index of the first match or the length of the whole
-- bytestring if nothing matched.
findIndexOrLength :: (Word16 -> Bool) -> ShortByteString -> Int
findIndexOrLength :: (Word16 -> Bool) -> ShortByteString -> Int
findIndexOrLength Word16 -> Bool
k (ShortByteString -> ShortByteString
assertEven -> ShortByteString
sbs) = Int -> Int
go Int
0
  where
    l :: Int
l = ShortByteString -> Int
BS.length ShortByteString
sbs
    ba :: BA
ba = ShortByteString -> BA
asBA ShortByteString
sbs
    w :: Int -> Word16
w = BA -> Int -> Word16
indexWord16Array BA
ba
    go :: Int -> Int
go !Int
n | Int
n forall a. Ord a => a -> a -> Bool
>= Int
l     = Int
l forall a. Integral a => a -> a -> a
`div` Int
2
          | Word16 -> Bool
k (Int -> Word16
w Int
n)    = Int
n forall a. Integral a => a -> a -> a
`div` Int
2
          | Bool
otherwise  = Int -> Int
go (Int
n forall a. Num a => a -> a -> a
+ Int
2)
{-# INLINE findIndexOrLength #-}


-- | Returns the length of the substring matching, not the index.
-- If no match, returns 0.
findFromEndUntil :: (Word16 -> Bool) -> ShortByteString -> Int
findFromEndUntil :: (Word16 -> Bool) -> ShortByteString -> Int
findFromEndUntil Word16 -> Bool
k ShortByteString
sbs = Int -> Int
go (ShortByteString -> Int
BS.length ShortByteString
sbs forall a. Num a => a -> a -> a
- Int
2)
  where
    ba :: BA
ba = ShortByteString -> BA
asBA ShortByteString
sbs
    w :: Int -> Word16
w = BA -> Int -> Word16
indexWord16Array BA
ba
    go :: Int -> Int
go !Int
n | Int
n forall a. Ord a => a -> a -> Bool
< Int
0     = Int
0
          | Word16 -> Bool
k (Int -> Word16
w Int
n)   = (Int
n forall a. Integral a => a -> a -> a
`div` Int
2) forall a. Num a => a -> a -> a
+ Int
1
          | Bool
otherwise = Int -> Int
go (Int
n forall a. Num a => a -> a -> a
- Int
2)
{-# INLINE findFromEndUntil #-}


assertEven :: ShortByteString -> ShortByteString
assertEven :: ShortByteString -> ShortByteString
assertEven sbs :: ShortByteString
sbs@(SBS ByteArray#
barr#)
  | forall a. Integral a => a -> Bool
even (Int# -> Int
I# (ByteArray# -> Int#
sizeofByteArray# ByteArray#
barr#)) = ShortByteString
sbs
  | Bool
otherwise = forall a. HasCallStack => [Char] -> a
error ([Char]
"Uneven number of bytes: " forall a. Semigroup a => a -> a -> a
<> forall a. Show a => a -> [Char]
show (ShortByteString -> Int
BS.length ShortByteString
sbs) forall a. Semigroup a => a -> a -> a
<> [Char]
". This is not a Word16 bytestream.")


-- Common up near identical calls to `error' to reduce the number
-- constant strings created when compiled:
errorEmptySBS :: HasCallStack => String -> a
errorEmptySBS :: forall a. HasCallStack => [Char] -> a
errorEmptySBS [Char]
fun = forall a. HasCallStack => [Char] -> [Char] -> a
moduleError [Char]
fun [Char]
"empty ShortByteString"
{-# NOINLINE errorEmptySBS #-}

moduleError :: HasCallStack => String -> String -> a
moduleError :: forall a. HasCallStack => [Char] -> [Char] -> a
moduleError [Char]
fun [Char]
msg = forall a. HasCallStack => [Char] -> a
error ([Char] -> [Char] -> [Char]
moduleErrorMsg [Char]
fun [Char]
msg)
{-# NOINLINE moduleError #-}

compareByteArraysOff :: BA  -- ^ array 1
                     -> Int -- ^ offset for array 1
                     -> BA  -- ^ array 2
                     -> Int -- ^ offset for array 2
                     -> Int -- ^ length to compare
                     -> Int -- ^ like memcmp
#if MIN_VERSION_base(4,11,0)
compareByteArraysOff :: BA -> Int -> BA -> Int -> Int -> Int
compareByteArraysOff (BA# ByteArray#
ba1#) (I# Int#
ba1off#) (BA# ByteArray#
ba2#) (I# Int#
ba2off#) (I# Int#
len#) =
  Int# -> Int
I# (ByteArray# -> Int# -> ByteArray# -> Int# -> Int# -> Int#
compareByteArrays#  ByteArray#
ba1# Int#
ba1off# ByteArray#
ba2# Int#
ba2off# Int#
len#)
#else
compareByteArraysOff (BA# ba1#) ba1off (BA# ba2#) ba2off len =
  assert (ba1off + len <= (I# (sizeofByteArray# ba1#)))
  $ assert (ba2off + len <= (I# (sizeofByteArray# ba2#)))
  $ fromIntegral $ accursedUnutterablePerformIO $
    c_memcmp_ByteArray ba1#
                       ba1off
                       ba2#
                       ba2off
                       (fromIntegral len)


foreign import ccall unsafe "static sbs_memcmp_off"
  c_memcmp_ByteArray :: ByteArray# -> Int -> ByteArray# -> Int -> CSize -> IO CInt
#endif