@@ -69,59 +69,65 @@ impl TextDiff {
69
69
/// Returns compressed text.
70
70
pub fn compress ( & mut self , data : & str ) -> & str {
71
71
let len = data. len ( ) ;
72
- let buf_len = self . buffer . len ( ) ;
73
- let history_len = self . buffer . len ( ) ;
72
+ let mut buf_len = self . buffer . len ( ) ;
73
+ let min_len = std :: cmp :: min ( len , buf_len ) ;
74
74
75
- // expand with new content
76
- if len > buf_len {
77
- self . buffer . push_str ( & data [ buf_len.. ] ) ;
78
- self . compressed . push_str ( & data [ buf_len.. ] . replace ( ' ' , "&" ) ) ; // copy & replace whitespaces
75
+ if buf_len > len {
76
+ // special case: shrink history
77
+ self . buffer = self . buffer [ ..len ] . to_string ( ) ;
78
+ buf_len = len ; // update size
79
79
}
80
80
81
- // study possible shared content
82
- let mut new = data. bytes ( ) ;
83
- let mut history = self . buffer [ ..history_len] . bytes ( ) ;
81
+ self . compressed = self . buffer . to_string ( ) ;
84
82
85
83
unsafe {
84
+ let mut bytes = data. as_bytes ( ) . iter ( ) ;
85
+ let mut buffered = self . buffer . as_bytes ( ) . iter ( ) ;
86
86
let mut compressed = self . compressed . as_bytes_mut ( ) . iter_mut ( ) ;
87
87
88
- // run through bytes for which we have history
89
- // and either keep or compress
90
- while let Some ( new ) = new . next ( ) {
91
- let compressed = compressed . next ( ) . unwrap ( ) ;
92
-
93
- if let Some ( history ) = history . next ( ) {
94
- if history == new {
95
- * compressed = b' ' ;
88
+ while let Some ( buffered ) = buffered . next ( ) {
89
+ let byte = bytes . next ( ) . unwrap ( ) ;
90
+ let mut compressed = compressed . next ( ) . unwrap ( ) ;
91
+ if byte == buffered {
92
+ * compressed = b' ' ;
93
+ } else {
94
+ if * byte == b' ' {
95
+ * compressed = b'& ' ;
96
96
} else {
97
- if new == b' ' {
98
- * compressed = b'&' ;
99
- } else {
100
- * compressed = new;
101
- }
97
+ * compressed = * byte;
102
98
}
103
99
}
104
100
}
101
+ }
105
102
106
- // supports shorter inputs than internal buffer:
107
- // possible '&' residues need to be whitened
108
- // this gives maximum flexibility when dealing with actual files
109
- while let Some ( compressed) = compressed. next ( ) {
110
- * compressed = b' ' ;
111
- }
103
+ // update internal memory
104
+ self . buffer = data. to_string ( ) ;
112
105
113
- self . buffer = data. to_string ( ) ;
114
- & self . compressed
106
+ // possible new string termination
107
+ if len > buf_len {
108
+ self . compressed . push_str ( & data[ buf_len..] ) ;
109
+
110
+ unsafe {
111
+ let mut compressed = self . compressed . as_bytes_mut ( ) . iter_mut ( ) . skip ( buf_len) ;
112
+ while let Some ( byte) = compressed. next ( ) {
113
+ if * byte == b' ' {
114
+ * byte = b'&' ;
115
+ }
116
+ }
117
+ }
115
118
}
119
+
120
+ & self . compressed
116
121
}
117
122
}
118
123
119
124
#[ cfg( test) ]
120
125
mod test {
121
126
use super :: * ;
122
127
#[ test]
123
- fn test_decompression ( ) {
124
- let mut diff = TextDiff :: new ( "ABCDEFG 12 000 33 XXACQmpLf" ) ;
128
+ fn textdiff_decompression ( ) {
129
+ const INIT : & str = "ABCDEFG 12 000 33 XXACQmpLf" ;
130
+ let mut diff = TextDiff :: new ( INIT ) ;
125
131
126
132
let compressed: Vec < & str > = vec ! [
127
133
" 3 1 44 xxACq F" ,
@@ -134,6 +140,7 @@ mod test {
134
140
"& " ,
135
141
" " ,
136
142
] ;
143
+
137
144
let expected: Vec < & str > = vec ! [
138
145
"ABCDEFG 13 001 44 xxACqmpLF" ,
139
146
"ABCDEFG 43 001 44 xxACqmpLF" ,
@@ -148,6 +155,7 @@ mod test {
148
155
149
156
for i in 0 ..compressed. len ( ) {
150
157
let decompressed = diff. decompress ( compressed[ i] ) ;
158
+
151
159
assert_eq ! (
152
160
decompressed,
153
161
expected[ i] ,
@@ -186,21 +194,23 @@ mod test {
186
194
}
187
195
188
196
#[ test]
189
- #[ ignore]
190
- fn test_compression ( ) {
197
+ fn textdiff_compression ( ) {
191
198
let mut diff = TextDiff :: new ( "0" ) ;
199
+
192
200
assert_eq ! ( diff. compress( "0" ) , " " ) ;
193
201
assert_eq ! ( diff. compress( "4" ) , "4" ) ;
194
202
assert_eq ! ( diff. compress( "4" ) , " " ) ;
203
+ assert_eq ! ( diff. compress( "44" ) , " 4" ) ;
195
204
assert_eq ! ( diff. compress( "4 " ) , " &" ) ;
205
+ assert_eq ! ( diff. compress( "4 " ) , " " ) ;
196
206
assert_eq ! ( diff. compress( "4 " ) , " &" ) ;
197
- assert_eq ! ( diff. compress( "0" ) , "0 " ) ;
198
- assert_eq ! ( diff. compress( "0" ) , " " ) ;
199
- assert_eq ! ( diff. compress( " " ) , "& " ) ;
207
+ assert_eq ! ( diff. compress( "0" ) , "0" ) ;
208
+ assert_eq ! ( diff. compress( "0" ) , " " ) ;
209
+ assert_eq ! ( diff. compress( " " ) , "&&& " ) ;
200
210
201
211
diff. force_init ( "Default 1234" ) ;
202
212
assert_eq ! ( diff. compress( "DEfault 1234" ) , " E " ) ;
203
213
assert_eq ! ( diff. compress( "DEfault 1234" ) , " " ) ;
204
- assert_eq ! ( diff. compress( " " ) , " &" ) ;
214
+ assert_eq ! ( diff. compress( " " ) , "&&&&&&& &&&& &" ) ;
205
215
}
206
216
}
0 commit comments