root/HTTP/Diff.lua

Revision 1281 (checked in by rsz, 1 year ago)

cleanup

Line 
1 --------------------------------------------------------------------------------
2 -- Title:               Diff.lua
3 -- Description:         Like a square peg in a round hole
4 -- Author:              Raphaël Szwarc http://alt.textdrive.com/lua/
5 -- Creation Date:       January 30, 2007
6 -- Legal:               Copyright (C) 2007 Raphaël Szwarc
7 --                      Under the terms of the MIT License
8 --                      http://www.opensource.org/licenses/mit-license.html
9 --------------------------------------------------------------------------------
10
11 -- As per Reuben Thomas's stdlib LCS module:
12 -- http://luaforge.net/projects/stdlib/
13 -- Based on pseudo-code in
14 -- http://www.ics.uci.edu/~eppstein/161/960229.html
15 -- Lecture notes by David Eppstein, eppstein@ics.uci.edu
16
17 -- import dependencies
18 local math = require( 'math' )
19 local table = require( 'table' )
20
21 local getmetatable = getmetatable
22 local setmetatable = setmetatable
23 local tostring = tostring
24
25 --------------------------------------------------------------------------------
26 -- Diff
27 --------------------------------------------------------------------------------
28
29 module( 'Diff' )
30 _VERSION = '1.0'
31
32 local self = setmetatable( _M, {} )
33 local meta = getmetatable( self )
34
35 --------------------------------------------------------------------------------
36 -- Utilities
37 --------------------------------------------------------------------------------
38
39 local function Token( aValue, aPattern, aLimit )
40     local aPattern = aPattern or '([%C]+)'
41     local aLimit = aLimit or 1000
42     local aList = {}
43     local hasMore = false
44    
45     for aToken in tostring( aValue ):gmatch( aPattern ) do
46         if #aList >= aLimit then
47             hasMore = true
48             break
49         end
50        
51         aList[ #aList + 1 ] = aToken
52     end
53    
54     return aList, hasMore
55 end
56
57 local function Sequence( listA, listB )
58     local max = math.max
59     local aList = {}
60     local lengthA = #listA
61     local lengthB = #listB
62
63     for indexA = lengthA + 1, 1, -1 do
64         aList[ indexA ] = {}
65        
66         for indexB = lengthB + 1, 1, -1 do
67             if indexA > lengthA or indexB > lengthB then
68                 aList[ indexA ][ indexB ] = 0
69             elseif listA[ indexA ] == listB[ indexB ] then
70                 aList[ indexA ][ indexB ] =  1 + aList[ indexA + 1 ][ indexB + 1 ]
71             else
72                 aList[ indexA ][ indexB ] = max( aList[ indexA + 1][ indexB ], aList[ indexA ][ indexB + 1 ] )
73             end
74         end
75     end
76
77     return aList, lengthA, lengthB
78 end
79
80 local function Diff( listA, listB, aHandler )
81     local aList, lengthA, lengthB = Sequence( listA, listB )
82     local indexA, indexB = 1, 1
83     local aBuffer = {}
84
85     while indexA <= lengthA or indexB <= lengthB do
86         if indexA > lengthA then
87             aBuffer[ #aBuffer + 1 ] = aHandler( '+', listB[ indexB ] )
88             indexB = indexB + 1
89         elseif indexB > lengthB then
90             aBuffer[ #aBuffer + 1 ] = aHandler( '-', listA[ indexA ] )
91             indexA = indexA + 1
92         elseif listA[ indexA ] == listB[ indexB ] then
93             aBuffer[ #aBuffer + 1 ] = aHandler( '=', listA[ indexA ] )
94             indexA = indexA + 1
95             indexB = indexB + 1
96         elseif aList[ indexA + 1 ][ indexB ] >= aList[ indexA ][ indexB + 1 ] then
97             aBuffer[ #aBuffer + 1 ] = aHandler( '-', listA[ indexA ] )
98             indexA = indexA + 1
99         else
100             aBuffer[ #aBuffer + 1 ] = aHandler( '+', listB[ indexB ] )
101             indexB = indexB + 1
102         end
103     end
104
105     return table.concat( aBuffer, ' ' )
106 end
107
108 local function Handler( aType, aValue )
109     if aType == '=' then
110         return aValue
111     end
112    
113     return ( '%s%s%s' ):format( aType, aValue, aType )   
114 end
115
116 --------------------------------------------------------------------------------
117 -- Metamethods
118 --------------------------------------------------------------------------------
119
120 function meta:__call( aTextA, aTextB, aHandler, aPattern, aLimit )
121     if aTextA and aTextB and aTextA ~= aTextB then
122         local aListA, hasMoreA = Token( aTextA, aPattern, aLimit )
123         local aListB, hasMoreB = Token( aTextB, aPattern, aLimit )
124         local aHandler = aHandler or Handler
125        
126         return Diff( aListA, aListB, aHandler ), hasMoreA or hasMoreB
127     end
128 end
129
130
Note: See TracBrowser for help on using the browser.