ram 0.20.1 → 0.22.1
raw patch · 11 files changed
Files
- CHANGELOG.md +42/−0
- Data/ByteArray/Bytes.hs +0/−1
- Data/ByteArray/Methods.hs +44/−2
- Data/ByteArray/ScrubbedBytes.hs +0/−1
- Data/ByteArray/Types.hs +0/−4
- Data/Memory/Internal/CompatPrim64.hs +0/−169
- Data/Memory/PtrMethods.hs +3/−3
- README.md +1/−1
- ram.cabal +1/−2
- tests/Imports.hs +11/−2
- tests/Tests.hs +26/−0
CHANGELOG.md view
@@ -1,3 +1,45 @@+## 0.22.1++ Use correct signatures for 'memset' and 'memcpy'+The WASM linker is more strict about function signatures matching, see https://releases.llvm.org/11.1.0/tools/lld/docs/WebAssembly.html#function-signatures++thanks @clinton-grc++## 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+ hashing. The `base16`, `base32`, `base64`, and `text` dependencies are removed+ again.++ Deleted `Data.Memory.Internal.CompatPrim64` (unreferenced).++ Added GitHub Actions CI (nix + cabal matrix).++## 0.21.0+++ `Data.ByteArray.Encoding`: replaced custom Base16/Base32/Base64 encode/decode+ with `base16`, `base32`, and `base64` library calls. Input is converted to+ `ByteString` via `B.convert`, the library function is applied, and the result+ is converted back. `Base64OpenBSD` retains its custom implementation (no+ library equivalent exists).++ `Data.ByteArray.Bytes`: replaced low-level `GHC.Prim` `MutableByteArray#`+ implementation with `newtype Bytes = Bytes ByteString`. Both use GHC's pinned+ allocator; `ByteString` already implements `ByteArrayAccess` / `ByteArray`.++ `Data.Memory.Hash.FNV`: replaced `readWord8OffAddr#` (GHC.Prim) with+ `Foreign.Storable.peekByteOff` — portable and equivalent.++ `Data.Memory.Internal.CompatPrim64`: deleted (was entirely unreferenced).++ New dependencies: `base16 >=1.0 && <2`, `base32 >=0.4 && <1`,+ `base64 >=1.0 && <2`, `text >=1.0 && <3`.++ Net reduction: ~350 lines removed.+ ## 0.20.1 + Remove `WITH_BYTESTRING_SUPPORT` CPP flag. `ByteString` instances for `ByteArrayAccess` and `ByteArray` are now always compiled in, since
Data/ByteArray/Bytes.hs view
@@ -25,7 +25,6 @@ import Data.Semigroup import Data.Foldable (toList) import Data.Memory.PtrMethods-import Data.Memory.Internal.Imports import Data.Memory.Internal.CompatPrim import Data.Memory.Internal.Compat (unsafeDoIO) import Data.ByteArray.Types
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
Data/ByteArray/ScrubbedBytes.hs view
@@ -33,7 +33,6 @@ import Data.Memory.PtrMethods import Data.Memory.Internal.CompatPrim import Data.Memory.Internal.Compat (unsafeDoIO)-import Data.Memory.Internal.Imports import Data.ByteArray.Types import Foreign.Storable
Data/ByteArray/Types.hs view
@@ -23,10 +23,6 @@ import Data.Memory.PtrMethods (memCopy) --import Data.Proxy (Proxy(..))-import Data.Word (Word8)- import Prelude hiding (length) -- | Class to Access size properties and data of a ByteArray
− Data/Memory/Internal/CompatPrim64.hs
@@ -1,169 +0,0 @@--- |--- Module : Data.Memory.Internal.CompatPrim--- License : BSD-style--- Maintainer : Vincent Hanquez <vincent@snarc.org>--- Stability : stable--- Portability : Compat------ This module try to keep all the difference between versions of ghc primitive--- or other needed packages, so that modules don't need to use CPP.------ Note that MagicHash and CPP conflicts in places, making it "more interesting"--- to write compat code for primitives----{-# LANGUAGE CPP #-}-{-# LANGUAGE BangPatterns #-}-{-# LANGUAGE MagicHash #-}-{-# LANGUAGE UnboxedTuples #-}-#include "MachDeps.h"-module Data.Memory.Internal.CompatPrim64- ( Word64#- , Int64#- , eqInt64#- , neInt64#- , ltInt64#- , leInt64#- , gtInt64#- , geInt64#- , quotInt64#- , remInt64#- , eqWord64#- , neWord64#- , ltWord64#- , leWord64#- , gtWord64#- , geWord64#- , and64#- , or64#- , xor64#- , not64#- , timesWord64#- , uncheckedShiftL64#- , uncheckedShiftRL64#-- , int64ToWord64#- , word64ToInt64#- , intToInt64#- , int64ToInt#- , wordToWord64#- , word64ToWord#- , w64#- ) where---#if WORD_SIZE_IN_BITS == 64-import GHC.Prim hiding (Word64#, Int64#)--#if __GLASGOW_HASKELL__ >= 708-type OutBool = Int#-#else-type OutBool = Bool-#endif--type Word64# = Word#-type Int64# = Int#--#if __GLASGOW_HASKELL__ < 904-eqWord64# :: Word64# -> Word64# -> OutBool-eqWord64# = eqWord#--neWord64# :: Word64# -> Word64# -> OutBool-neWord64# = neWord#--ltWord64# :: Word64# -> Word64# -> OutBool-ltWord64# = ltWord#--leWord64# :: Word64# -> Word64# -> OutBool-leWord64# = leWord#--gtWord64# :: Word64# -> Word64# -> OutBool-gtWord64# = gtWord#--geWord64# :: Word64# -> Word64# -> OutBool-geWord64# = geWord#--eqInt64# :: Int64# -> Int64# -> OutBool-eqInt64# = (==#)--neInt64# :: Int64# -> Int64# -> OutBool-neInt64# = (/=#)--ltInt64# :: Int64# -> Int64# -> OutBool-ltInt64# = (<#)--leInt64# :: Int64# -> Int64# -> OutBool-leInt64# = (<=#)--gtInt64# :: Int64# -> Int64# -> OutBool-gtInt64# = (>#)--geInt64# :: Int64# -> Int64# -> OutBool-geInt64# = (<=#)--quotInt64# :: Int64# -> Int64# -> Int64#-quotInt64# = quotInt#--remInt64# :: Int64# -> Int64# -> Int64#-remInt64# = remInt#--and64# :: Word64# -> Word64# -> Word64#-and64# = and#--or64# :: Word64# -> Word64# -> Word64#-or64# = or#--xor64# :: Word64# -> Word64# -> Word64#-xor64# = xor#--not64# :: Word64# -> Word64#-not64# = not#--uncheckedShiftL64# :: Word64# -> Int# -> Word64#-uncheckedShiftL64# = uncheckedShiftL#--uncheckedShiftRL64# :: Word64# -> Int# -> Word64#-uncheckedShiftRL64# = uncheckedShiftL#--int64ToWord64# :: Int64# -> Word64#-int64ToWord64# = int2Word#--word64ToInt64# :: Word64# -> Int64#-word64ToInt64# = word2Int#--intToInt64# :: Int# -> Int64#-intToInt64# w = w--int64ToInt# :: Int64# -> Int#-int64ToInt# w = w--wordToWord64# :: Word# -> Word64#-wordToWord64# w = w--word64ToWord# :: Word64# -> Word#-word64ToWord# w = w--timesWord64# :: Word64# -> Word64# -> Word64#-timesWord64# = timesWord#-#endif--w64# :: Word# -> Word# -> Word# -> Word64#-w64# w _ _ = w--#elif WORD_SIZE_IN_BITS == 32-import GHC.IntWord64-import GHC.Prim (Word#)--timesWord64# :: Word64# -> Word64# -> Word64#-timesWord64# a b =- let !ai = word64ToInt64# a- !bi = word64ToInt64# b- in int64ToWord64# (timesInt64# ai bi)--w64# :: Word# -> Word# -> Word# -> Word64#-w64# _ hw lw =- let !h = wordToWord64# hw- !l = wordToWord64# lw- in or64# (uncheckedShiftL64# h 32#) l-#else-#error "not a supported architecture. supported WORD_SIZE_IN_BITS is 32 bits or 64 bits"-#endif
Data/Memory/PtrMethods.hs view
@@ -63,7 +63,7 @@ -- | Copy a set number of bytes from @src to @dst memCopy :: Ptr Word8 -> Ptr Word8 -> Int -> IO ()-memCopy dst src n = c_memcpy dst src (fromIntegral n)+memCopy dst src n = c_memcpy dst src (fromIntegral n) >>= \_ -> return () {-# INLINE memCopy #-} -- | Set @n number of bytes to the same value @v@@ -114,7 +114,7 @@ loop (i+1) (acc .|. e) foreign import ccall unsafe "memset"- c_memset :: Ptr Word8 -> Word8 -> CSize -> IO ()+ c_memset :: Ptr Word8 -> Word8 -> CSize -> IO (Ptr Word8) foreign import ccall unsafe "memcpy"- c_memcpy :: Ptr Word8 -> Ptr Word8 -> CSize -> IO ()+ c_memcpy :: Ptr Word8 -> Ptr Word8 -> CSize -> IO (Ptr Word8)
README.md view
@@ -1,4 +1,4 @@-memory+ram ====== [](http://en.wikipedia.org/wiki/BSD_licenses)
ram.cabal view
@@ -1,6 +1,6 @@ cabal-version: 3.0 name: ram-version: 0.20.1+version: 0.22.1 synopsis: memory and related abstraction stuff description: This is a fork of memory. It's open to accept changes from anyone,@@ -65,7 +65,6 @@ Data.Memory.Hash.SipHash Data.Memory.Internal.Compat Data.Memory.Internal.CompatPrim- Data.Memory.Internal.CompatPrim64 Data.Memory.Internal.Imports exposed-modules: Data.ByteArray.Sized
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)) ]