packages feed

byteslice 0.1.1.0 → 0.1.2.0

raw patch · 5 files changed

+200/−3 lines, 5 filesdep +run-stPVP ok

version bump matches the API change (PVP)

Dependencies added: run-st

API changes (from Hackage documentation)

+ Data.Bytes: data Bytes
+ Data.Bytes: dropWhile :: (Word8 -> Bool) -> Bytes -> Bytes
+ Data.Bytes: fromAsciiString :: String -> Bytes
+ Data.Bytes: fromByteArray :: ByteArray -> Bytes
+ Data.Bytes: length :: Bytes -> Int
+ Data.Bytes: null :: Bytes -> Bool
+ Data.Bytes: takeWhile :: (Word8 -> Bool) -> Bytes -> Bytes
+ Data.Bytes: toByteArray :: Bytes -> ByteArray
+ Data.Bytes: toByteArrayClone :: Bytes -> ByteArray
+ Data.Bytes: unsafeDrop :: Int -> Bytes -> Bytes
+ Data.Bytes: unsafeTake :: Int -> Bytes -> Bytes
+ Data.Bytes.Mutable: data MutableBytes s
+ Data.Bytes.Mutable: dropWhile :: PrimMonad m => (Word8 -> m Bool) -> MutableBytes (PrimState m) -> m (MutableBytes (PrimState m))
+ Data.Bytes.Mutable: fromMutableByteArray :: PrimMonad m => MutableByteArray (PrimState m) -> m (MutableBytes (PrimState m))
+ Data.Bytes.Mutable: takeWhile :: PrimMonad m => (Word8 -> m Bool) -> MutableBytes (PrimState m) -> m (MutableBytes (PrimState m))
+ Data.Bytes.Mutable: unsafeDrop :: Int -> MutableBytes s -> MutableBytes s
+ Data.Bytes.Mutable: unsafeTake :: Int -> MutableBytes s -> MutableBytes s

Files

CHANGELOG.md view
@@ -1,5 +1,10 @@ # Revision history for byteslice +## 0.1.2.0 -- 2019-08-21++* Add `Data.Bytes.Mutable` module.+* Add `Data.Bytes` module.+ ## 0.1.1.0 -- 2019-07-03  * Add record labels for Bytes and MutableBytes
byteslice.cabal view
@@ -1,6 +1,6 @@ cabal-version: 2.2 name: byteslice-version: 0.1.1.0+version: 0.1.2.0 synopsis: Slicing managed and unmanaged memory description:   This library provides types that allow the user to talk about a slice of@@ -19,10 +19,14 @@  library   exposed-modules:+    Data.Bytes+    Data.Bytes.Mutable     Data.Bytes.Types   build-depends:     , base >=4.11.1.0 && <5     , primitive >=0.7 && <0.8-    , primitive-addr >= 0.1 && <0.2+    , primitive-addr >=0.1 && <0.2+    , run-st >=0.1 && <0.2   hs-source-dirs: src+  ghc-options: -Wall -O2   default-language: Haskell2010
+ src/Data/Bytes.hs view
@@ -0,0 +1,103 @@+{-# language BangPatterns #-}+{-# language TypeApplications #-}++module Data.Bytes+  ( -- * Types+    Bytes+    -- * Properties+  , null+  , length+    -- * Filtering+  , takeWhile+  , dropWhile+    -- * Unsafe Slicing+  , unsafeTake+  , unsafeDrop+    -- * Conversion+  , toByteArray+  , toByteArrayClone+  , fromAsciiString+  , fromByteArray+  ) where++import Prelude hiding (length,takeWhile,dropWhile,null)++import Data.Bytes.Types (Bytes(Bytes))+import Data.Primitive (ByteArray)+import Data.Word (Word8)+import Data.Char (ord)+import Control.Monad.ST.Run (runByteArrayST)++import qualified Data.Primitive as PM+import qualified GHC.Exts as Exts++-- | Is the byte sequence empty?+null :: Bytes -> Bool+null (Bytes _ _ len) = len == 0++-- | The length of a slice of bytes.+length :: Bytes -> Int+length (Bytes _ _ len) = len++-- | Take bytes while the predicate is true.+takeWhile :: (Word8 -> Bool) -> Bytes -> Bytes+{-# inline takeWhile #-}+takeWhile k b = unsafeTake (countWhile k b) b++-- | Drop bytes while the predicate is true.+dropWhile :: (Word8 -> Bool) -> Bytes -> Bytes+{-# inline dropWhile #-}+dropWhile k b = unsafeDrop (countWhile k b) b++-- | Take the first @n@ bytes from the argument. Precondition: @n ≤ len@+unsafeTake :: Int -> Bytes -> Bytes+{-# inline unsafeTake #-}+unsafeTake n (Bytes arr off _) =+  Bytes arr off n++-- | Drop the first @n@ bytes from the argument. Precondition: @n ≤ len@+unsafeDrop :: Int -> Bytes -> Bytes+{-# inline unsafeDrop #-}+unsafeDrop n (Bytes arr off len) =+  Bytes arr (off + n) (len - n)++-- Internal. The returns the number of bytes that match the+-- predicate until the first non-match occurs. If all bytes+-- match the predicate, this will return the length originally+-- provided.+countWhile :: (Word8 -> Bool) -> Bytes -> Int+{-# inline countWhile #-}+countWhile k (Bytes arr off0 len0) = go off0 len0 0 where+  go !off !len !n = if len > 0+    then if k (PM.indexByteArray arr off)+      then go (off + 1) (len - 1) (n + 1)+      else n+    else n++-- | Convert the sliced 'Bytes' to an unsliced 'ByteArray'. This+-- reuses the array backing the sliced 'Bytes' if the slicing metadata+-- implies that all of the bytes are used. Otherwise, it makes a copy.+toByteArray :: Bytes -> ByteArray+toByteArray b@(Bytes arr off len)+  | off /= 0 = toByteArrayClone b+  | PM.sizeofByteArray arr /= len = toByteArrayClone b+  | otherwise = arr++-- | Variant of 'toByteArray' that unconditionally makes a copy of+-- the array backing the sliced 'Bytes' even if the original array+-- could be reused. Prefer 'toByteArray'.+toByteArrayClone :: Bytes -> ByteArray+toByteArrayClone (Bytes arr off len) = runByteArrayST $ do+  m <- PM.newByteArray len+  PM.copyByteArray m 0 arr off len+  PM.unsafeFreezeByteArray m++-- | Convert a 'String' consisting of only characters+--   in the ASCII block.+fromAsciiString :: String -> Bytes+fromAsciiString = fromByteArray . Exts.fromList . map (fromIntegral @Int @Word8 . ord)++-- | Create a slice of 'Bytes' that spans the entire argument array.+fromByteArray :: ByteArray -> Bytes+fromByteArray b = Bytes b 0 (PM.sizeofByteArray b)+
+ src/Data/Bytes/Mutable.hs view
@@ -0,0 +1,85 @@+{-# language BangPatterns #-}+{-# language LambdaCase #-}++module Data.Bytes.Mutable+  ( -- * Types+    MutableBytes+    -- * Filtering+  , takeWhile+  , dropWhile+    -- * Unsafe Slicing+  , unsafeTake+  , unsafeDrop+    -- * Conversion+  , fromMutableByteArray+  ) where++import Prelude hiding (takeWhile,dropWhile)++import Data.Bytes.Types (MutableBytes(MutableBytes))+import Data.Primitive (MutableByteArray)+import Data.Word (Word8)+import Control.Monad.Primitive (PrimMonad,PrimState)++import qualified Data.Primitive as PM++-- | Take bytes while the predicate is true, aliasing the+-- argument array.+takeWhile :: PrimMonad m+  => (Word8 -> m Bool)+  -> MutableBytes (PrimState m)+  -> m (MutableBytes (PrimState m))+{-# inline takeWhile #-}+takeWhile k b = do+  n <- countWhile k b+  pure (unsafeTake n b)++-- | Drop bytes while the predicate is true, aliasing the+-- argument array.+dropWhile :: PrimMonad m+  => (Word8 -> m Bool)+  -> MutableBytes (PrimState m)+  -> m (MutableBytes (PrimState m))+{-# inline dropWhile #-}+dropWhile k b = do+  n <- countWhile k b+  pure (unsafeDrop n b)++-- | Take the first @n@ bytes from the argument, aliasing it.+unsafeTake :: Int -> MutableBytes s -> MutableBytes s+{-# inline unsafeTake #-}+unsafeTake n (MutableBytes arr off _) =+  MutableBytes arr off n++-- | Drop the first @n@ bytes from the argument, aliasing it.+-- The new length will be @len - n@.+unsafeDrop :: Int -> MutableBytes s -> MutableBytes s+{-# inline unsafeDrop #-}+unsafeDrop n (MutableBytes arr off len) =+  MutableBytes arr (off + n) (len - n)++-- | Create a slice of 'MutableBytes' that spans the entire+-- argument array. This aliases the argument.+fromMutableByteArray :: PrimMonad m+  => MutableByteArray (PrimState m)+  -> m (MutableBytes (PrimState m))+{-# inline fromMutableByteArray #-}+fromMutableByteArray mba = do+  sz <- PM.getSizeofMutableByteArray mba+  pure (MutableBytes mba 0 sz)++-- Internal. The returns the number of bytes that match the+-- predicate until the first non-match occurs. If all bytes+-- match the predicate, this will return the length originally+-- provided.+countWhile :: PrimMonad m+  => (Word8 -> m Bool)+  -> MutableBytes (PrimState m)+  -> m Int+{-# inline countWhile #-}+countWhile k (MutableBytes arr off0 len0) = go off0 len0 0 where+  go !off !len !n = if len > 0+    then (k =<< PM.readByteArray arr off) >>= \case+      True -> go (off + 1) (len - 1) (n + 1)+      False -> pure n+    else pure n
src/Data/Bytes/Types.hs view
@@ -54,7 +54,7 @@   else []  instance Show Bytes where-  showsPrec d (Bytes arr off len) s = if len == 0+  showsPrec _ (Bytes arr off len) s = if len == 0     then showString "[]" s     else showString "[0x"        $ showHexDigits (PM.indexByteArray arr off)