summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorJoe Crayne <joe@jerkface.net>2018-10-30 15:57:08 -0400
committerJoe Crayne <joe@jerkface.net>2018-10-30 19:53:36 -0400
commit5faf6a665e87ac67cbe5cf67cffb2aa90b56de92 (patch)
treed86cbeaf82f447bfecd564db553bd70933d933b5
parent9a8a11acafe6110b9a243c5c42a3db854d8213dc (diff)
Refactored xdelta function, enables lazier streaming.
-rw-r--r--haskell/Data/VCDIFF.hs79
-rw-r--r--haskell/Data/VCDIFF/XDelta.hsc3
-rw-r--r--haskell/examples/testdiff.hs15
-rw-r--r--xdelta.cabal2
4 files changed, 87 insertions, 12 deletions
diff --git a/haskell/Data/VCDIFF.hs b/haskell/Data/VCDIFF.hs
index 6b95ede..f06be9c 100644
--- a/haskell/Data/VCDIFF.hs
+++ b/haskell/Data/VCDIFF.hs
@@ -24,6 +24,7 @@ module Data.VCDIFF
24 , computeDiff 24 , computeDiff
25 , applyPatch) where 25 , applyPatch) where
26 26
27-- import Debug.Trace
27import Control.Monad 28import Control.Monad
28import Control.Monad.Primitive 29import Control.Monad.Primitive
29import Control.Monad.ST 30import Control.Monad.ST
@@ -34,6 +35,7 @@ import qualified Data.ByteString.Unsafe as B
34import qualified Data.ByteString.Internal as B 35import qualified Data.ByteString.Internal as B
35import qualified Data.ByteString.Lazy as L 36import qualified Data.ByteString.Lazy as L
36import Data.Coerce 37import Data.Coerce
38import Data.Function
37import Data.Int 39import Data.Int
38import qualified Data.IntMap as IntMap 40import qualified Data.IntMap as IntMap
39import Data.Monoid 41import Data.Monoid
@@ -87,6 +89,7 @@ config_stream cfg = do
87 xd3_abort_stream sptr 89 xd3_abort_stream sptr
88 xd3_close_stream sptr 90 xd3_close_stream sptr
89 xd3_free_stream sptr 91 xd3_free_stream sptr
92 putStrLn $ "finalized " ++ show sptr
90 keepAlive srcvar s 93 keepAlive srcvar s
91 fp <- newForeignPtr sptr finalize 94 fp <- newForeignPtr sptr finalize
92 return Stream 95 return Stream
@@ -104,7 +107,7 @@ set_source :: PrimMonad m =>
104 -> Usize_t -- ^ block size 107 -> Usize_t -- ^ block size
105 -> Xoff_t -- ^ maximum visible buffer (Suggested: set same as block size). 108 -> Xoff_t -- ^ maximum visible buffer (Suggested: set same as block size).
106 -- Rounds up to approx 16k. 109 -- Rounds up to approx 16k.
107 -> m () 110 -> m (Source m)
108set_source stream nm blksz maxwinsz = do 111set_source stream nm blksz maxwinsz = do
109 src <- newSource nm blksz maxwinsz 112 src <- newSource nm blksz maxwinsz
110 {- 113 {-
@@ -115,6 +118,7 @@ set_source stream nm blksz maxwinsz = do
115 let strm = streamArrayPtr $ streamArray stream 118 let strm = streamArrayPtr $ streamArray stream
116 unsafeIOToPrim (xd3_set_source strm $ sourcePtr src) 119 unsafeIOToPrim (xd3_set_source strm $ sourcePtr src)
117 writeMutVar (streamSource stream) (Just src) 120 writeMutVar (streamSource stream) (Just src)
121 return src
118 122
119data XDeltaMethods m u = XDeltaMethods 123data XDeltaMethods m u = XDeltaMethods
120 { xConfig :: Config 124 { xConfig :: Config
@@ -159,17 +163,78 @@ withByteString d act =
159 unsafeIOToPrim $ touchForeignPtr fp 163 unsafeIOToPrim $ touchForeignPtr fp
160 return a 164 return a
161 165
162xdelta :: (PrimBase m, Monoid u) => XDeltaMethods m u -> (Stream m -> m ErrorCode) -> [B.ByteString] -> m u 166outputChunks :: (Monoid b, Num t, PrimMonad m, Show b) =>
163xdelta x xxcode_input ds = do 167 StreamArray m
168 -> (m b -> m b)
169 -> m ErrorCode
170 -> (Ptr Word8 -> t -> m b)
171 -> (ErrorCode -> m b)
172 -> m b
173outputChunks strm interleave encode output next = fix $ \loop -> do
174 encode >>= \case
175 XD3_OUTPUT -> do u1 <- nextOut strm $ \(p,len) -> output p (fromIntegral len)
176 trace ("u1 = " ++ show u1) $ return ()
177 u <- interleave $ loop
178 return $ u1 <> u
179 XD3_GOTHEADER -> trace "XD3_GOTHEADER" loop
180 XD3_WINSTART -> trace "XD3_WINSTART" loop
181 XD3_WINFINISH -> trace "XD3_WINFINISH" loop
182 xd3 -> next xd3
183
184withBlocks :: PrimBase m => B.ByteString -> Maybe B.ByteString -> m a -> m a
185withBlocks d mblk f = withByteString d $ \_ _ -> case mblk of
186 Just blk -> withByteString blk $ \_ _ -> f
187 Nothing -> f
188
189updateBlock :: (Monoid u, PrimBase m, Show u) =>
190 Stream m
191 -> m ErrorCode
192 -> Maybe B.ByteString
193 -> XDeltaMethods m u
194 -> B.ByteString
195 -> [B.ByteString]
196 -> ErrorCode
197 -> m u
198updateBlock stream code_input mblk x _ [] XD3_INPUT = return mempty
199updateBlock stream code_input mblk x _ (d:ds) XD3_INPUT = trace "XD3_INPUT" $ do
200 withByteString d $ \p len -> avail_input (streamArray stream) p len
201 when (null ds) $ setFlush (streamArray stream) True
202 outputChunks (streamArray stream) (xInterleave x)
203 (withBlocks d mblk code_input)
204 (xOutput x)
205 $ updateBlock stream code_input mblk x d ds
206updateBlock stream code_input mblk x d ds XD3_GETSRCBLK = do
207 Just n <- requestedBlockNumber stream
208 let blk = xGetSource x n
209 withByteString blk $ \p len -> do
210 pokeCurrentBlock stream $ CurrentBlock n len p
211 trace ("XD3_GETSRCBLK " ++ show (n,len,p,xBlockSize x)) $ return ()
212 when (len < xBlockSize x) $ do
213 Just src <- readMutVar $ streamSource stream
214 sourceWriteEOFKnown src True
215 outputChunks (streamArray stream) (xInterleave x)
216 (withBlocks d (Just blk) code_input)
217 (xOutput x)
218 $ updateBlock stream code_input mblk x d ds
219updateBlock stream code_input mblk x d ds e = trace (show e) $ do
220 s <- errorString (streamArray stream)
221 xOnError x e s
222
223trace _ = id
224
225xdelta :: (Show u, PrimBase m, Monoid u) => XDeltaMethods m u -> (Stream m -> m ErrorCode) -> [B.ByteString] -> m u
226xdelta x xxcode_input ds = trace ("ds = "++show ds) $ do
164 mstream <- config_stream (xConfig x) 227 mstream <- config_stream (xConfig x)
165 either (\e _ -> xOnError x e "config_stream failed") 228 either (\e _ -> xOnError x e "config_stream failed")
166 (flip ($)) 229 (flip ($))
167 mstream $ \stream -> do 230 mstream $ \stream -> do
168 set_source stream "VCDIFF" (xBlockSize x) (xBlockSize x) 231 src <- set_source stream "VCDIFF" (xBlockSize x) (xBlockSize x)
232 updateBlock stream (xxcode_input stream) Nothing x B.empty ds XD3_INPUT
233 {-
169 let go withBlk [] = return mempty 234 let go withBlk [] = return mempty
170 go withBlk (d:ds) = do 235 go withBlk (d:ds) = do
171 let (fp,off,len) = B.toForeignPtr d 236 let (fp,off,len) = B.toForeignPtr d
172 eof = null ds 237 eof = null ds || len < fromIntegral (xBlockSize x)
173 when eof $ setFlush (streamArray stream) True 238 when eof $ setFlush (streamArray stream) True
174 withByteString d $ \indata len -> do 239 withByteString d $ \indata len -> do
175 avail_input (streamArray stream) indata len 240 avail_input (streamArray stream) indata len
@@ -203,7 +268,7 @@ xdelta x xxcode_input ds = do
203 s <- errorString (streamArray stream) 268 s <- errorString (streamArray stream)
204 xOnError x e s 269 xOnError x e s
205 xInterleave x $ go id ds 270 xInterleave x $ go id ds
206 271 -}
207 272
208decode_input :: PrimMonad m => Stream m -> m ErrorCode 273decode_input :: PrimMonad m => Stream m -> m ErrorCode
209decode_input stream = 274decode_input stream =
@@ -271,7 +336,7 @@ xdeltaPure codec cfg source input =
271 <$> B.packCStringLen (castPtr ptr,len) 336 <$> B.packCStringLen (castPtr ptr,len)
272 , xOnError = \e s -> return (Result L.empty (Just (e,s))) 337 , xOnError = \e s -> return (Result L.empty (Just (e,s)))
273 , xBlockSize = bsize 338 , xBlockSize = bsize
274 , xInterleave = unsafeInterleaveST 339 , xInterleave = id -- unsafeInterleaveST
275 } 340 }
276 in runST $ xdelta x codec ds 341 in runST $ xdelta x codec ds
277 342
diff --git a/haskell/Data/VCDIFF/XDelta.hsc b/haskell/Data/VCDIFF/XDelta.hsc
index b406c1d..c66dab2 100644
--- a/haskell/Data/VCDIFF/XDelta.hsc
+++ b/haskell/Data/VCDIFF/XDelta.hsc
@@ -75,7 +75,8 @@ sourceWriteCurrentBlock :: PrimMonad m => Source m -> CurrentBlock -> m ()
75sourceWriteCurrentBlock (Source src) (CurrentBlock no sz ptr) = do 75sourceWriteCurrentBlock (Source src) (CurrentBlock no sz ptr) = do
76 writeAtByte src (#{off xd3_source, curblkno}) no 76 writeAtByte src (#{off xd3_source, curblkno}) no
77 writeAtByte src (#{off xd3_source, onblk}) sz 77 writeAtByte src (#{off xd3_source, onblk}) sz
78 writeAtByte src (#{off xd3_source, curblk}) ptr 78 when (ptr /= nullPtr)
79 $ writeAtByte src (#{off xd3_source, curblk}) ptr
79 80
80sourceWriteEOFKnown :: PrimMonad m => Source m -> Bool -> m () 81sourceWriteEOFKnown :: PrimMonad m => Source m -> Bool -> m ()
81sourceWriteEOFKnown (Source src) False = writeAtByte src (#{off xd3_source, eof_known}) (0 :: #{type int}) 82sourceWriteEOFKnown (Source src) False = writeAtByte src (#{off xd3_source, eof_known}) (0 :: #{type int})
diff --git a/haskell/examples/testdiff.hs b/haskell/examples/testdiff.hs
index 9d580ba..08229d3 100644
--- a/haskell/examples/testdiff.hs
+++ b/haskell/examples/testdiff.hs
@@ -17,7 +17,7 @@ delta :: Result VCDIFF
17delta = computeDiff defaultConfig source target 17delta = computeDiff defaultConfig source target
18 18
19delta2 :: Result VCDIFF 19delta2 :: Result VCDIFF
20delta2 = computeDiff defaultConfig source target 20delta2 = computeDiff defaultConfig source target
21 21
22delta3 :: Result VCDIFF 22delta3 :: Result VCDIFF
23delta3 = computeDiff defaultConfig { flags = XD3_ADLER32 } source target 23delta3 = computeDiff defaultConfig { flags = XD3_ADLER32 } source target
@@ -25,6 +25,9 @@ delta3 = computeDiff defaultConfig { flags = XD3_ADLER32 } source target
25delta4 :: Result VCDIFF 25delta4 :: Result VCDIFF
26delta4 = computeDiff defaultConfig { flags = XD3_ADLER32 } source target 26delta4 = computeDiff defaultConfig { flags = XD3_ADLER32 } source target
27 27
28delta5 :: Result VCDIFF
29delta5 = computeDiff defaultConfig { flags = XD3_ADLER32 } source target
30
28 31
29 32
30dump title bs kont = do 33dump title bs kont = do
@@ -35,14 +38,20 @@ dump title bs kont = do
35main = do 38main = do
36 dump "source" source $ putStrLn "" 39 dump "source" source $ putStrLn ""
37 dump "target" target $ putStrLn "" 40 dump "target" target $ putStrLn ""
38 go source "default" delta
39 go source "default" delta2
40 go source "XD3_ADLER32" delta3 41 go source "XD3_ADLER32" delta3
41 go source "XD3_ADLER32" delta4 42 go source "XD3_ADLER32" delta4
43 go source "XD3_ADLER32" delta5
44 go source "default" delta
45 go source "default" delta2
46 {-
42 go source2 "default" delta 47 go source2 "default" delta
43 go source2 "default" delta2 48 go source2 "default" delta2
44 go source2 "XD3_ADLER32" delta3 49 go source2 "XD3_ADLER32" delta3
45 go source2 "XD3_ADLER32" delta4 50 go source2 "XD3_ADLER32" delta4
51 -}
52 print source
53 print source2
54 print target
46 55
47go source flgs delta = do 56go source flgs delta = do
48 putStrLn "" 57 putStrLn ""
diff --git a/xdelta.cabal b/xdelta.cabal
index d54f3f6..0097e9f 100644
--- a/xdelta.cabal
+++ b/xdelta.cabal
@@ -21,7 +21,7 @@ library
21 21
22 build-tools: hsc2hs 22 build-tools: hsc2hs
23 include-dirs: haskell . 23 include-dirs: haskell .
24 cpp-options: -DNOT_MAIN=1 -DREGRESSION_TEST=1 -DSECONDARY_DJW=1 -DSECONDARY_FGK=1 -DXD3_MAIN=1 -DXD3_DEBUG=0 -DHAVE_CONFIG 24 cpp-options: -DNOT_MAIN=1 -DREGRESSION_TEST=1 -DSECONDARY_DJW=1 -DSECONDARY_FGK=1 -DXD3_MAIN=1 -DXD3_DEBUG=3 -DHAVE_CONFIG
25 cxx-options: -Wno-literal-suffix -g 25 cxx-options: -Wno-literal-suffix -g
26 cxx-sources: haskell/xdelta3.cc 26 cxx-sources: haskell/xdelta3.cc
27 27