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 +5/−0
- byteslice.cabal +6/−2
- src/Data/Bytes.hs +103/−0
- src/Data/Bytes/Mutable.hs +85/−0
- src/Data/Bytes/Types.hs +1/−1
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)