packages feed

ram 0.21.1 → 0.22.0

raw patch · 5 files changed

+93/−5 lines, 5 files

Files

CHANGELOG.md view
@@ -1,3 +1,14 @@+## 0.22.0++ Added `slice :: ByteArray bs => bs -> Int -> Int -> Maybe bs`+  and `unsafeSlice :: ByteArray bs => bs -> Int -> Int -> bs`+  to `Data.ByteArray.Methods` (re-exported via `Data.ByteArray`).+  `slice bs offset len` extracts `len` bytes starting at `offset`.+  Returns `Nothing` for negative offset/length or out-of-bounds access.+  `unsafeSlice` calls `error` on invalid arguments. (closes #7)++ Added `map :: (ByteArrayAccess ba, ByteArray ba) => (Word8 -> Word8) -> ba -> ba`+  to `Data.ByteArray.Methods` (re-exported via `Data.ByteArray`).+  Applies a function to each byte of a byte array. (closes #5)+ ## 0.21.1 + Reverted 0.21.0 changes: restored custom Base16/Base32/Base64 encode/decode,   the GHC.Prim-based `Bytes` implementation, and `readWord8OffAddr#`-based FNV
Data/ByteArray/Methods.hs view
@@ -39,6 +39,9 @@     , all     , append     , concat+    , map+    , slice+    , unsafeSlice     ) where  import           Data.ByteArray.Types@@ -49,7 +52,7 @@ import           Foreign.Storable import           Foreign.Ptr -import           Prelude hiding (length, take, drop, span, reverse, concat, replicate, splitAt, null, pred, last, any, all)+import           Prelude hiding (length, take, drop, span, reverse, concat, replicate, splitAt, null, pred, last, any, all, map) import qualified Prelude  @@ -200,7 +203,7 @@ concat :: (ByteArrayAccess bin, ByteArray bout) => [bin] -> bout concat l = unsafeCreate retLen (loopCopy l)   where-    retLen = sum $ map length l+    retLen = sum $ Prelude.map length l      loopCopy []     _   = return ()     loopCopy (x:xs) dst = do@@ -296,6 +299,45 @@ all :: (ByteArrayAccess ba) => (Word8 -> Bool) -> ba -> Bool all f b = not (any (not . f) b) +-- | Map a function over each byte of a bytearray+map :: (ByteArrayAccess ba, ByteArray ba) => (Word8 -> Word8) -> ba -> ba+map f ba = copyAndFreeze ba $ loop 0+  where+    len = length ba+    loop i ptr+        | i == len  = return ()+        | otherwise = do+            let ptr' = ptr `plusPtr` i+            x <- peek ptr'+            poke ptr' $ f x+            loop (i + 1) ptr+ -- | Convert a bytearray to another type of bytearray convert :: (ByteArrayAccess bin, ByteArray bout) => bin -> bout convert bs = inlineUnsafeCreate (length bs) (copyByteArrayToPtr bs)++-- | Extract @len@ bytes starting at byte @offset@.+-- Returns 'Nothing' if @offset@ or @len@ is negative, or if @offset + len@+-- exceeds the byte array length.+slice :: ByteArray bs => bs -> Int -> Int -> Maybe bs+slice bs offset len+    | offset < 0           = Nothing+    | len < 0              = Nothing+    | offset + len > bsLen = Nothing+    | otherwise            = Just $ unsafeCreate len $ \d ->+        withByteArray bs $ \s -> memCopy d (s `plusPtr` offset) len+  where+    bsLen = length bs++-- | Like 'slice' but calls 'error' when arguments are out of bounds.+-- This includes negative @offset@, negative @len@, or @offset + len@+-- exceeding the byte array length.+unsafeSlice :: ByteArray bs => bs -> Int -> Int -> bs+unsafeSlice bs offset len+    | offset < 0           = error "unsafeSlice: negative offset"+    | len < 0              = error "unsafeSlice: negative length"+    | offset + len > bsLen = error "unsafeSlice: offset + length exceeds byte array size"+    | otherwise            = unsafeCreate len $ \d ->+        withByteArray bs $ \s -> memCopy d (s `plusPtr` offset) len+  where+    bsLen = length bs
ram.cabal view
@@ -1,6 +1,6 @@ cabal-version:   3.0 name:            ram-version:         0.21.1+version:         0.22.0 synopsis:        memory and related abstraction stuff description:   This is a fork of memory. It's open to accept changes from anyone,
tests/Imports.hs view
@@ -5,6 +5,7 @@     , testCase     , assertBool     , assertEqual+    , assertException     , (@?=)     ) where @@ -16,13 +17,13 @@ import Test.QuickCheck              as X     ( Arbitrary(..), Gen, Property     , (===), (.&&.)-    , elements, choose, forAll, property, ioProperty+    , elements, choose, forAll, property, ioProperty, (==>)     , Testable     )  import Test.Tasty.Providers         (singleTest, IsTest(..), testPassed, testFailed) import Test.QuickCheck              (quickCheckWithResult, stdArgs, isSuccess, Args(..))-import Control.Exception            (SomeException, try)+import Control.Exception            (SomeException, ErrorCall, try, evaluate)  -- | QuickCheck property test provider for tasty newtype QCTest = QCTest Property@@ -71,3 +72,11 @@ actual @?= expected     | actual == expected = return ()     | otherwise = fail ("expected: " ++ show expected ++ "\n but got: " ++ show actual)++-- | Assert that evaluating a value throws an 'ErrorCall' exception.+assertException :: forall a . a -> IO ()+assertException val = do+    r <- try (evaluate val) :: IO (Either ErrorCall a)+    case r of+        Left _  -> return ()+        Right _ -> fail "expected an exception but none was thrown"
tests/Tests.hs view
@@ -248,4 +248,30 @@         , testProperty "span (const False)" $ \(Words8 l) ->             let b = witnessID (B.pack l)              in B.span (const False) b == (B.empty, b)+        , testProperty "map f == pack . Prelude.map f . unpack" $ \(Words8 l) (Positive w) ->+            let b = witnessID (B.pack l)+                f x = x + fromIntegral w :: Word8+             in B.map f b == (witnessID . B.pack . Prelude.map f $ l)+        , testProperty "slice == Just (take len . drop offset)" $ \(Words8 l) ->+            let bs = witnessID (B.pack l)+                bsLen = B.length bs+            in bsLen > 0 ==>+               forAll (choose (0, bsLen)) $ \offset ->+               forAll (choose (0, bsLen - offset)) $ \len ->+                 B.slice bs offset len == Just (B.take len (B.drop offset bs))+        , testProperty "slice out of bounds == Nothing" $ \(Words8 l) ->+            let bs = witnessID (B.pack l)+                bsLen = B.length bs+            in B.slice bs 0 (bsLen + 1) == Nothing+        , testProperty "slice negative offset == Nothing" $ \(Words8 l) ->+            let bs = witnessID (B.pack l)+            in B.slice bs (-1) 0 == Nothing+        , testProperty "slice negative length == Nothing" $ \(Words8 l) ->+            let bs = witnessID (B.pack l)+            in B.slice bs 0 (-1) == Nothing+        , testCase "unsafeSlice errors on out of bounds" $ do+            let bs = witnessID (B.pack [1,2,3,4,5])+            assertException (B.unsafeSlice bs (-1) 1)+            assertException (B.unsafeSlice bs 0 (-1))+            assertException (B.unsafeSlice bs 0 (B.length bs + 1))         ]