1 #ifndef _WDL_DIFFCALC_H_
2 #define _WDL_DIFFCALC_H_
4 #include "assocarray.h"
8 // Based on "An O(ND) Difference Algorithm and Its Variations", Myers
9 // http://xmailserver.org/diff2.pdf
12 template <class T
> class WDL_DiffCalc
16 virtual ~WDL_DiffCalc() {}
18 // cmp() returns 0 if the elements are equal.
19 // returns the length of the merged list and populates m_rx, m_ry.
20 int Diff(const T
* x
, const T
* y
, int nx
, int ny
, int (*cmp
)(const T
*, const T
*))
22 m_rx
.Resize(0, false);
23 m_ry
.Resize(0, false);
26 if (!nx
&& !ny
) return 0;
32 m_rx
.Add(nx
? i
: -1);
33 m_ry
.Add(ny
? i
: -1);
38 if (!cmp(x
, y
)) // special case
41 for (n
=1; n
< min(nx
, ny
); ++n
)
43 if (cmp(x
+n
, y
+n
)) break;
45 int len
=Diff(x
+n
, y
+n
, nx
-n
, ny
-n
, cmp
);
46 int *rx
=m_rx
.Get(), *ry
=m_ry
.Get();
47 for (i
=0; i
< len
; ++i
)
49 if (rx
[i
] >= 0) rx
[i
] += n
;
50 if (ry
[i
] >= 0) ry
[i
] += n
;
63 for (d
=0; d
<= nx
+ny
; ++d
)
65 for (k
=-d
; k
<= d
; k
+= 2)
67 if (k
== -d
|| (k
!= d
&& GetV(d
, k
-1) < GetV(d
, k
+1)))
76 while (xi
< nx
&& yi
< ny
&& !cmp(x
+xi
, y
+yi
))
82 if (xi
>= nx
&& yi
>= ny
) break;
84 if (xi
>= nx
&& yi
>= ny
) break;
88 int *rx
=m_rx
.Resize(len
);
89 int *ry
=m_ry
.Resize(len
);
94 while (xi
> 0 && yi
> 0 && !cmp(x
+xi
-1, y
+yi
-1))
101 if (k
== -d
|| (k
!= d
&& GetV(d
, k
-1) < GetV(d
, k
+1)))
119 // m_rx, m_ry hold the index of each merged list element in x and y,
120 // or -1 if the merged list element is not an element in that source list.
121 // example: X="ABCABBA", Y="CBABAC"
123 // WDL_Merge() returns "ABCBABBAC"
126 // m_rx={ 0, 1, 2, -1, 3, 4, 5, 6, -1}
127 // m_ry={-1, -1, 0, 1, 2, 3, -1, 4, 5}
128 WDL_TypedBuf
<int> m_rx
, m_ry
;
132 WDL_IntKeyedArray
<int> m_v
; // x coord of d-contour on row k
137 void SetV(int d
, int k
, int xi
)
139 m_v
.Insert(_key(d
, k
), xi
);
141 int GetV(int d
, int k
)
143 return m_v
.Get(_key(d
, k
));
145 static int _key(int d
, int k
) { return (d
<<16)|(k
+(1<<15)); }
149 // this is a separate function from WDL_DiffCalc only because it requires T::operator=
150 template <class T
> int WDL_Merge(const T
* x
, const T
* y
, int nx
, int ny
,
151 int (*cmp
)(const T
*, const T
*), T
* list
)
154 int i
, n
=dc
.Diff(x
, y
, nx
, ny
, cmp
);
155 int *rx
=dc
.m_rx
.Get(), *ry
=dc
.m_ry
.Get();
156 for (i
=0; i
< n
; ++i
)
158 if (list
) list
[i
]=(rx
[i
] >= 0 ? x
[rx
[i
]] : y
[ry
[i
]]);