summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorJoe Crayne <joe@jerkface.net>2018-10-25 19:24:54 -0400
committerJoe Crayne <joe@jerkface.net>2018-10-25 19:24:54 -0400
commitf8bb9011375e39b71fe1764159e034a97ea70f2e (patch)
tree52e8c6b52e28d6fb891cc3e4f206e8f4e759ea8b
parent604ab9ded08cf1f2f7ed0f3109d0cc11984f55ea (diff)
it works
-rw-r--r--examples/testdiff.hs10
-rw-r--r--haskell/Data/XDelta.hsc44
-rw-r--r--haskell/XDelta/Types.hsc3
-rw-r--r--xdelta3.cabal10
4 files changed, 41 insertions, 26 deletions
diff --git a/examples/testdiff.hs b/examples/testdiff.hs
index 4ed7dd4..9360545 100644
--- a/examples/testdiff.hs
+++ b/examples/testdiff.hs
@@ -19,5 +19,11 @@ main = do
19 mapM_ putStrLn $ xxd2 0 (L.toStrict patched) 19 mapM_ putStrLn $ xxd2 0 (L.toStrict patched)
20 putStrLn "" 20 putStrLn ""
21 case delta of 21 case delta of
22 XSuccess (XDelta d) -> mapM_ putStrLn $ xxd2 0 (L.toChunks d !! 0) 22 XResult δ@(XDelta d) me -> do
23 _ -> print delta 23 -- mapM_ (mapM_ putStrLn . xxd2 0) (chunksOf 16 d)
24 mapM_ putStrLn $ xxd2 0 (L.toStrict d)
25 print me
26 putStrLn ""
27 let XResult patched' pe = applyPatch defaultConfig source δ
28 mapM_ putStrLn $ xxd2 0 (L.toStrict patched') -- $ L.take 48 patched')
29 print pe
diff --git a/haskell/Data/XDelta.hsc b/haskell/Data/XDelta.hsc
index 4ebdd51..bb08cb6 100644
--- a/haskell/Data/XDelta.hsc
+++ b/haskell/Data/XDelta.hsc
@@ -30,7 +30,6 @@ import Data.STRef
30import qualified Data.Text as T 30import qualified Data.Text as T
31import Data.Text.Encoding 31import Data.Text.Encoding
32import Data.Word 32import Data.Word
33import Debug.Trace
34import Foreign.C.Types 33import Foreign.C.Types
35import Foreign.C.String 34import Foreign.C.String
36import Foreign.ForeignPtr (withForeignPtr) 35import Foreign.ForeignPtr (withForeignPtr)
@@ -53,7 +52,10 @@ import XDelta.Types
53 52
54data Stream m = Stream 53data Stream m = Stream
55 { streamArray :: MutableByteArray (PrimState m) 54 { streamArray :: MutableByteArray (PrimState m)
56 , streamPtr :: ForeignPtr Xd3Stream 55 , streamPtr :: ForeignPtr Xd3Stream -- ^ HACK: this is only used to attach a finalizer
56 -- to 'streamArray'. Don't use this pointer.
57 -- This would be unnecessary if I could create a
58 -- MutableByteArray with a finalizer attached.
57 , streamSource :: MutVar (PrimState m) (Maybe (MutableByteArray (PrimState m))) 59 , streamSource :: MutVar (PrimState m) (Maybe (MutableByteArray (PrimState m)))
58 } 60 }
59 61
@@ -138,6 +140,7 @@ config_stream cfg = do
138 xd3_abort_stream sptr 140 xd3_abort_stream sptr
139 xd3_close_stream sptr 141 xd3_close_stream sptr
140 xd3_free_stream sptr 142 xd3_free_stream sptr
143 seq s $ return () -- Keep array s alive until the ffi functions finish.
141 fp <- newForeignPtr sptr finalize 144 fp <- newForeignPtr sptr finalize
142 return Stream 145 return Stream
143 { streamArray = s 146 { streamArray = s
@@ -278,7 +281,8 @@ xdelta x xxcode_input ds = do
278 (flip ($)) 281 (flip ($))
279 mstream $ \stream -> do 282 mstream $ \stream -> do
280 set_source stream "xdelta" (xBlockSize x) (xBlockSize x) 283 set_source stream "xdelta" (xBlockSize x) (xBlockSize x)
281 let go withBlk (d:ds) = do 284 let go withBlk [] = return mempty
285 go withBlk (d:ds) = do
282 let (fp,off,len) = B.toForeignPtr d 286 let (fp,off,len) = B.toForeignPtr d
283 eof = null ds 287 eof = null ds
284 when eof $ setFlush stream True 288 when eof $ setFlush stream True
@@ -291,9 +295,8 @@ xdelta x xxcode_input ds = do
291 XD3_INPUT -> if (not eof) then go withBlk ds else return mempty 295 XD3_INPUT -> if (not eof) then go withBlk ds else return mempty
292 XD3_OUTPUT -> do 296 XD3_OUTPUT -> do
293 m' <- nextOut stream (\(p,len) -> xOutput x p (fromIntegral len)) 297 m' <- nextOut stream (\(p,len) -> xOutput x p (fromIntegral len))
294 ms <- xInterleave x $ undefined -- go2 withBlk eof ds 298 ms <- xInterleave x $ go2 withBlk eof ds
295 return $ trace "chunk" m' <> ms 299 return $ m' <> ms
296 -- XXX: This output is to test for laziness.
297 XD3_GETSRCBLK -> do 300 XD3_GETSRCBLK -> do
298 Just n <- requestedBlockNumber stream 301 Just n <- requestedBlockNumber stream
299 let blk = xGetSource x n 302 let blk = xGetSource x n
@@ -314,7 +317,7 @@ xdelta x xxcode_input ds = do
314 e -> do 317 e -> do
315 s <- errorString stream 318 s <- errorString stream
316 xOnError x e s 319 xOnError x e s
317 go id ds 320 xInterleave x $ go id ds
318 321
319 322
320foreign import ccall "xdelta3.h xd3_decode_input" xd3_decode_input :: Ptr Xd3Stream -> IO ErrorCode 323foreign import ccall "xdelta3.h xd3_decode_input" xd3_decode_input :: Ptr Xd3Stream -> IO ErrorCode
@@ -342,39 +345,36 @@ computeDiff cfg source patched = fmap XDelta $ xdeltaPure encode_input cfg sourc
342applyPatch :: Config -> L.ByteString -> XDelta -> XDeltaFailable L.ByteString 345applyPatch :: Config -> L.ByteString -> XDelta -> XDeltaFailable L.ByteString
343applyPatch cfg source (XDelta delta) = xdeltaPure decode_input cfg source delta 346applyPatch cfg source (XDelta delta) = xdeltaPure decode_input cfg source delta
344 347
345data XDeltaFailable x = XError ErrorCode String 348data XDeltaFailable x = XResult { xresult :: x, xerror :: (Maybe (ErrorCode,String)) }
346 | XSuccess x
347 deriving (Show,Functor) 349 deriving (Show,Functor)
348 350
349instance Monoid x => Monoid (XDeltaFailable x) where 351instance Monoid x => Monoid (XDeltaFailable x) where
350 mempty = XSuccess mempty 352 mempty = XResult mempty Nothing
351 mappend (XSuccess x) (XSuccess y) = XSuccess $ mappend x y 353 mappend (XResult x xe) y = XResult (mappend x $ xresult y) (maybe (xerror y) Just xe)
352 mappend x@XError{} _ = x
353 mappend _ y@XError{} = y
354 354
355xdeltaPure :: (forall s. Stream (ST s) -> ST s ErrorCode) -> Config -> L.ByteString -> L.ByteString -> XDeltaFailable L.ByteString 355xdeltaPure :: (forall s. Stream (ST s) -> ST s ErrorCode) -> Config -> L.ByteString -> L.ByteString -> XDeltaFailable L.ByteString
356xdeltaPure codec cfg source delta = 356xdeltaPure codec cfg source delta =
357 let smap = IntMap.fromList $ zip [0..] (chunksOf 16 source) 357 let smap = IntMap.fromList $ zip [0..] (chunksOf bsize source)
358 bsize = 4096
358 x :: XDeltaMethods (ST s) (XDeltaFailable L.ByteString) 359 x :: XDeltaMethods (ST s) (XDeltaFailable L.ByteString)
359 x = XDeltaMethods 360 x = XDeltaMethods
360 { xConfig = cfg 361 { xConfig = cfg
361 , xGetSource = \i -> case IntMap.lookup (fromIntegral i) smap of 362 , xGetSource = \i -> case IntMap.lookup (fromIntegral i) smap of
362 Nothing -> B.empty 363 Nothing -> B.empty
363 Just bs -> bs 364 Just bs -> bs
364 , xOutput = \ptr len -> unsafeIOToST $ XSuccess . L.fromStrict <$> B.packCStringLen (castPtr ptr,len) 365 , xOutput = \ptr len -> unsafeIOToST $ flip XResult Nothing . L.fromStrict <$> B.packCStringLen (castPtr ptr,len)
365 , xOnError = \e s -> return (XError e s) -- :: ErrorCode -> String -> m u 366 , xOnError = \e s -> return (XResult L.empty (Just (e,s))) -- :: ErrorCode -> String -> m u
366 , xBlockSize = 16 -- 4096 -- :: Usize_t 367 , xBlockSize = bsize -- :: Usize_t
367 , xInterleave = unsafeInterleaveST -- :: forall a. m a -> m a 368 , xInterleave = unsafeInterleaveST -- :: forall a. m a -> m a
368 -- XXX: Why isn't unsafeInterleaveST making it lazy?
369 } 369 }
370 ds = chunksOf 16 delta -- L.toChunks delta 370 ds = chunksOf bsize delta -- L.toChunks delta
371 in runST $ xdelta x codec ds 371 in runST $ xdelta x codec ds
372 372
373defaultConfig :: Config 373defaultConfig :: Config
374defaultConfig = Config 374defaultConfig = Config
375 { winsize = 4096 375 { winsize = XD3_DEFAULT_WINSIZE
376 , sprevsz = 0 376 , sprevsz = XD3_DEFAULT_SPREVSZ
377 , iopt_size = 0 377 , iopt_size = XD3_DEFAULT_IOPT_SIZE
378 , flags = mempty 378 , flags = mempty
379 , sec_data = CompressorConfig 0 0 0 379 , sec_data = CompressorConfig 0 0 0
380 , sec_inst = CompressorConfig 0 0 0 380 , sec_inst = CompressorConfig 0 0 0
diff --git a/haskell/XDelta/Types.hsc b/haskell/XDelta/Types.hsc
index f1d98ce..a0f2cfa 100644
--- a/haskell/XDelta/Types.hsc
+++ b/haskell/XDelta/Types.hsc
@@ -115,6 +115,9 @@ data Config = Config
115 , smatch_cfg :: Either StringMatcher SMatchSelect -- ^ See enum: use fields below for soft config 115 , smatch_cfg :: Either StringMatcher SMatchSelect -- ^ See enum: use fields below for soft config
116 } 116 }
117 117
118pattern XD3_DEFAULT_WINSIZE = #const XD3_DEFAULT_WINSIZE
119pattern XD3_DEFAULT_SPREVSZ = #const XD3_DEFAULT_SPREVSZ
120pattern XD3_DEFAULT_IOPT_SIZE = #const XD3_DEFAULT_IOPT_SIZE
118 121
119newtype Flags = Flags Word32 122newtype Flags = Flags Word32
120 deriving (Storable,Eq,Bits,FiniteBits) 123 deriving (Storable,Eq,Bits,FiniteBits)
diff --git a/xdelta3.cabal b/xdelta3.cabal
index e773d6e..bc8a81b 100644
--- a/xdelta3.cabal
+++ b/xdelta3.cabal
@@ -25,7 +25,7 @@ library
25 -- extra-lib-dirs: xdelta3_lib 25 -- extra-lib-dirs: xdelta3_lib
26 include-dirs: haskell . 26 include-dirs: haskell .
27 -- cc-options: -std=c++14 -Wno-literal-suffix 27 -- cc-options: -std=c++14 -Wno-literal-suffix
28 cxx-options: -Wno-literal-suffix 28 cxx-options: -Wno-literal-suffix -g
29 cpp-options: -DNOT_MAIN=1 -DREGRESSION_TEST=1 -DSECONDARY_DJW=1 -DSECONDARY_FGK=1 -DXD3_MAIN=1 -DXD3_DEBUG=0 -DHAVE_CONFIG 29 cpp-options: -DNOT_MAIN=1 -DREGRESSION_TEST=1 -DSECONDARY_DJW=1 -DSECONDARY_FGK=1 -DXD3_MAIN=1 -DXD3_DEBUG=0 -DHAVE_CONFIG
30 -- cpp-options: -DHAVE_CONFIG_H -DSIZEOF_SIZE_T=__SIZEOF_SIZE_T__ -DSIZEOF_UNSIGNED_INT=__SIZEOF_INT__ -DSIZEOF_UNSIGNED_LONG=__SIZEOF_LONG__ 30 -- cpp-options: -DHAVE_CONFIG_H -DSIZEOF_SIZE_T=__SIZEOF_SIZE_T__ -DSIZEOF_UNSIGNED_INT=__SIZEOF_INT__ -DSIZEOF_UNSIGNED_LONG=__SIZEOF_LONG__
31 -- cpp-options: -DSIZEOF_UNSIGNED_LONG_LONG=__SIZEOF_LONG_LONG__ 31 -- cpp-options: -DSIZEOF_UNSIGNED_LONG_LONG=__SIZEOF_LONG_LONG__
@@ -34,7 +34,7 @@ library
34 cxx-sources: haskell/xdelta3.cc 34 cxx-sources: haskell/xdelta3.cc
35 35
36 hs-source-dirs: haskell 36 hs-source-dirs: haskell
37 build-depends: base >=4.10, bytestring, text, primitive, containers 37 build-depends: base >=4.9, bytestring, text, primitive >=0.6.2, containers
38 default-language: Haskell2010 38 default-language: Haskell2010
39 ghc-options: -Wmissing-signatures 39 ghc-options: -Wmissing-signatures
40 40
@@ -43,3 +43,9 @@ executable testdiff
43 other-modules: Text.XXD 43 other-modules: Text.XXD
44 hs-source-dirs: haskell examples . 44 hs-source-dirs: haskell examples .
45 build-depends: base, bytestring, memory, xdelta 45 build-depends: base, bytestring, memory, xdelta
46
47executable lazy
48 main-is: lazy.hs
49 other-modules: Text.XXD
50 hs-source-dirs: haskell examples .
51 build-depends: base, bytestring, memory, xdelta