spool (empty) → 0.1
raw patch · 6 files changed
+199/−0 lines, 6 filesdep +basedep +bytestringdep +vectorsetup-changed
Dependencies added: base, bytestring, vector
Files
- Data/Vector/Storable/ByteString.hs +36/−0
- LICENSE +26/−0
- README +10/−0
- Setup.hs +4/−0
- spool.cabal +38/−0
- test/test.hs +85/−0
+ Data/Vector/Storable/ByteString.hs view
@@ -0,0 +1,36 @@+-- | Convert between @ByteString@ and @Vector.Storable@+-- without copying.+module Data.Vector.Storable.ByteString+ ( -- | See also the caveats mentioned in the package's+ -- top-level documentation.+ byteStringToVector+ , vectorToByteString+ ) where++import qualified Data.ByteString as BS+import qualified Data.ByteString.Internal as BS+import qualified Data.Vector.Storable as V++import Foreign.Storable+import Foreign.ForeignPtr++sizeOfElem :: (Storable a) => V.Vector a -> Int+sizeOfElem vec = sizeOf (undefined `asTypeOf` V.head vec)++-- | Convert a @'BS.ByteString'@ to a @'V.Vector'@.+--+-- This function can produce @'Vector'@s which do not obey+-- architectural alignment requirements. On @x86@ this should+-- not be an issue.+byteStringToVector :: (Storable a) => BS.ByteString -> V.Vector a+byteStringToVector bs = vec where+ vec = V.unsafeFromForeignPtr (castForeignPtr fptr) (scale off) (scale len)+ (fptr, off, len) = BS.toForeignPtr bs+ scale = (`div` sizeOfElem vec)++-- | Convert a @'V.Vector'@ to a @'BS.ByteString'@.+vectorToByteString :: (Storable a) => V.Vector a -> BS.ByteString+vectorToByteString vec+ = BS.fromForeignPtr (castForeignPtr fptr) (scale off) (scale len) where+ (fptr, off, len) = V.unsafeToForeignPtr vec+ scale = (* sizeOfElem vec)
+ LICENSE view
@@ -0,0 +1,26 @@+Copyright (c) Keegan McAllister 2011++All rights reserved.++Redistribution and use in source and binary forms, with or without+modification, are permitted provided that the following conditions+are met:+1. Redistributions of source code must retain the above copyright+ notice, this list of conditions and the following disclaimer.+2. Redistributions in binary form must reproduce the above copyright+ notice, this list of conditions and the following disclaimer in the+ documentation and/or other materials provided with the distribution.+3. Neither the name of the author nor the names of his contributors+ may be used to endorse or promote products derived from this software+ without specific prior written permission.++THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS ``AS IS''+AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE+IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE+DISCLAIMED. IN NO EVENT SHALL THE AUTHORS OR CONTRIBUTORS BE LIABLE FOR ANY+DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES+(INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;+LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON+ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT+(INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS+SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ README view
@@ -0,0 +1,10 @@+spool provides conversion between ByteString and Vector.Storable without+copying the underlying data.++Documentation is hosted at http://hackage.haskell.org/package/spool++To build the documentation yourself, run++ $ cabal configure && cabal haddock --hyperlink-source++This will produce HTML documentation under dist/doc/html/spool.
+ Setup.hs view
@@ -0,0 +1,4 @@+#! /usr/bin/runhaskell++import Distribution.Simple+main = defaultMain
+ spool.cabal view
@@ -0,0 +1,38 @@+name: spool+version: 0.1+license: BSD3+license-file: LICENSE+synopsis: Convert between ByteString and Vector.Storable without copying+category: Data Structures+author: Keegan McAllister <mcallister.keegan@gmail.com>+maintainer: Keegan McAllister <mcallister.keegan@gmail.com>+build-type: Simple+cabal-version: >=1.6+description:+ This library allows conversion between the types from @Data.ByteString@+ (package @bytestring@) and @Data.Vector.Storable@ (package @vector@) without+ copying the underlying data. This is useful, for example, when @ByteString@+ IO produces or consumes vectors of numbers in native byte order.+ .+ This trick relies on the fact that @ByteString@ and @Vector@ use their+ respective @ForeignPtr@s in compatible ways. It works with+ @bytestring-0.9.1.10@ and @vector-0.9@ on GHC 7.0. It may break with future+ releases of these packages. Depending on this library should be seen as a+ way to document and standardize an existing hack, and not as an absolute+ guarantee of correct behavior.++extra-source-files:+ test/test.hs+ , README++library+ exposed-modules: Data.Vector.Storable.ByteString+ ghc-options: -Wall+ build-depends:+ base >= 3 && < 5+ , bytestring >= 0.9+ , vector >= 0.7++source-repository head+ type: git+ location: git://github.com/kmcallister/spool.git
+ test/test.hs view
@@ -0,0 +1,85 @@+{-# LANGUAGE+ ScopedTypeVariables #-}++module Main(main) where++import qualified Data.ByteString as B+import qualified Data.Vector.Storable as V++import Data.Word+import System.ByteOrder -- package 'byteorder'+import Test.QuickCheck+import Foreign.Storable++import Data.Vector.Storable.ByteString+++arbList :: (Bounded a, Integral a) => Gen [a]+arbList = choose (0, 16384) >>= flip vectorOf arbitraryBoundedIntegral++instance Arbitrary B.ByteString where+ arbitrary = fmap B.pack arbList++instance (Bounded a, Integral a, Storable a) => Arbitrary (V.Vector a) where+ arbitrary = fmap V.fromList arbList+++-- Reference implementations++fromBE, fromHost :: (Integral a) => [Word8] -> a+fromBE = foldl (\n x -> n*256 + fromIntegral x) 0+fromHost = case byteOrder of+ LittleEndian -> fromBE . reverse+ BigEndian -> fromBE++toLE, toHost :: (Integral a) => Int -> a -> [Word8]+toLE sz = take sz . map (fromIntegral . (`mod` 256)) . iterate (`div` 256)+toHost = case byteOrder of+ LittleEndian -> toLE+ BigEndian -> \sz -> reverse . toLE sz++data Rep a = Rep Int ([Word8] -> a) (a -> [Word8])++rep8 :: Rep Word8+rep8 = Rep 1 (\[x] -> x) return++repN :: forall a. (Storable a, Integral a) => Rep a+repN = let n = sizeOf (undefined :: a) in Rep n fromHost (toHost n)++ref_byteStringToVector :: (Storable a) => Rep a -> B.ByteString -> V.Vector a+ref_byteStringToVector (Rep n f _) = V.fromList . go where+ go bs = case B.splitAt n bs of+ (x, xs) | B.length x == n -> f (B.unpack x) : go xs+ _ -> []++ref_vectorToByteString :: (Storable a) => Rep a -> V.Vector a -> B.ByteString+ref_vectorToByteString (Rep _ _ f) = B.pack . concatMap f . V.toList+++-- Properties++mkProp_inv _ x = byteStringToVector (vectorToByteString x) == x+mkProp_inv_ref r x = ref_byteStringToVector r (ref_vectorToByteString r x) == x++mkProp_inv_ref1 r x = ref_byteStringToVector r (vectorToByteString x) == x+mkProp_inv_ref2 r x = byteStringToVector (ref_vectorToByteString r x) == x++mkProp_eq_BV r x = ref_byteStringToVector r x == byteStringToVector x+mkProp_eq_VB r x = ref_vectorToByteString r x == vectorToByteString x+++-- Test runner++runFor :: (Integral a, Bounded a, Storable a) => Rep a -> IO ()+runFor r = do+ mapM_ (quickCheck . ($r))+ [mkProp_inv, mkProp_inv_ref, mkProp_inv_ref1,+ mkProp_inv_ref2, mkProp_eq_VB]+ quickCheck (mkProp_eq_BV r)++main :: IO ()+main = do+ runFor rep8+ runFor (repN :: Rep Word16)+ runFor (repN :: Rep Word32)+ runFor (repN :: Rep Word64)