@@ -18,6 +18,7 @@ use std::cast;
18
18
use std:: cell:: RefCell ;
19
19
use std:: cmp:: Equiv ;
20
20
use std:: hashmap:: HashMap ;
21
+ use std:: rc:: Rc ;
21
22
22
23
pub struct Interner < T > {
23
24
priv map: @RefCell < HashMap < T , Name > > ,
@@ -83,11 +84,49 @@ impl<T:Eq + IterBytes + Hash + Freeze + Clone + 'static> Interner<T> {
83
84
}
84
85
}
85
86
87
+ #[ deriving( Clone , Eq , IterBytes , Ord ) ]
88
+ pub struct RcStr {
89
+ priv string : Rc < ~str > ,
90
+ }
91
+
92
+ impl TotalEq for RcStr {
93
+ fn equals ( & self , other : & RcStr ) -> bool {
94
+ self . as_slice ( ) . equals ( & other. as_slice ( ) )
95
+ }
96
+ }
97
+
98
+ impl TotalOrd for RcStr {
99
+ fn cmp ( & self , other : & RcStr ) -> Ordering {
100
+ self . as_slice ( ) . cmp ( & other. as_slice ( ) )
101
+ }
102
+ }
103
+
104
+ impl Str for RcStr {
105
+ #[ inline]
106
+ fn as_slice < ' a > ( & ' a self ) -> & ' a str {
107
+ let s: & ' a str = * self . string . borrow ( ) ;
108
+ s
109
+ }
110
+
111
+ #[ inline]
112
+ fn into_owned ( self ) -> ~str {
113
+ self . string . borrow ( ) . to_owned ( )
114
+ }
115
+ }
116
+
117
+ impl RcStr {
118
+ pub fn new ( string : & str ) -> RcStr {
119
+ RcStr {
120
+ string : Rc :: new ( string. to_owned ( ) ) ,
121
+ }
122
+ }
123
+ }
124
+
86
125
// A StrInterner differs from Interner<String> in that it accepts
87
126
// references rather than @ ones, resulting in less allocation.
88
127
pub struct StrInterner {
89
- priv map: @RefCell < HashMap < @ str , Name > > ,
90
- priv vect : @RefCell < ~[ @ str ] > ,
128
+ priv map: @RefCell < HashMap < RcStr , Name > > ,
129
+ priv vect : @RefCell < ~[ RcStr ] > ,
91
130
}
92
131
93
132
// when traits can extend traits, we should extend index<Name,T> to get []
@@ -113,8 +152,8 @@ impl StrInterner {
113
152
}
114
153
115
154
let new_idx = self . len ( ) as Name ;
116
- let val = val . to_managed ( ) ;
117
- map. get ( ) . insert ( val, new_idx) ;
155
+ let val = RcStr :: new ( val ) ;
156
+ map. get ( ) . insert ( val. clone ( ) , new_idx) ;
118
157
let mut vect = self . vect . borrow_mut ( ) ;
119
158
vect. get ( ) . push ( val) ;
120
159
new_idx
@@ -124,7 +163,7 @@ impl StrInterner {
124
163
let new_idx = self . len ( ) as Name ;
125
164
// leave out of .map to avoid colliding
126
165
let mut vect = self . vect . borrow_mut ( ) ;
127
- vect. get ( ) . push ( val . to_managed ( ) ) ;
166
+ vect. get ( ) . push ( RcStr :: new ( val ) ) ;
128
167
new_idx
129
168
}
130
169
@@ -142,21 +181,21 @@ impl StrInterner {
142
181
let new_idx = self . len ( ) as Name ;
143
182
// leave out of map to avoid colliding
144
183
let mut vect = self . vect . borrow_mut ( ) ;
145
- let existing = vect. get ( ) [ idx] ;
184
+ let existing = vect. get ( ) [ idx] . clone ( ) ;
146
185
vect. get ( ) . push ( existing) ;
147
186
new_idx
148
187
}
149
188
150
- pub fn get ( & self , idx : Name ) -> @ str {
189
+ pub fn get ( & self , idx : Name ) -> RcStr {
151
190
let vect = self . vect . borrow ( ) ;
152
- vect. get ( ) [ idx]
191
+ vect. get ( ) [ idx] . clone ( )
153
192
}
154
193
155
194
/// Returns this string with lifetime tied to the interner. Since
156
195
/// strings may never be removed from the interner, this is safe.
157
196
pub fn get_ref < ' a > ( & ' a self , idx : Name ) -> & ' a str {
158
197
let vect = self . vect . borrow ( ) ;
159
- let s: & str = vect. get ( ) [ idx] ;
198
+ let s: & str = vect. get ( ) [ idx] . as_slice ( ) ;
160
199
unsafe {
161
200
cast:: transmute ( s)
162
201
}
@@ -167,7 +206,7 @@ impl StrInterner {
167
206
vect. get ( ) . len ( )
168
207
}
169
208
170
- pub fn find_equiv < Q : Hash + IterBytes + Equiv < @ str > > ( & self , val : & Q )
209
+ pub fn find_equiv < Q : Hash + IterBytes + Equiv < RcStr > > ( & self , val : & Q )
171
210
-> Option < Name > {
172
211
let map = self . map . borrow ( ) ;
173
212
match map. get ( ) . find_equiv ( val) {
@@ -183,42 +222,46 @@ mod tests {
183
222
#[ test]
184
223
#[ should_fail]
185
224
fn i1 ( ) {
186
- let i : Interner < @ str > = Interner :: new ( ) ;
225
+ let i : Interner < RcStr > = Interner :: new ( ) ;
187
226
i. get ( 13 ) ;
188
227
}
189
228
190
229
#[ test]
191
230
fn interner_tests ( ) {
192
- let i : Interner < @ str > = Interner :: new ( ) ;
231
+ let i : Interner < RcStr > = Interner :: new ( ) ;
193
232
// first one is zero:
194
- assert_eq ! ( i. intern( @ "dog" ) , 0 ) ;
233
+ assert_eq ! ( i. intern( RcStr :: new ( "dog" ) ) , 0 ) ;
195
234
// re-use gets the same entry:
196
- assert_eq ! ( i. intern( @ "dog" ) , 0 ) ;
235
+ assert_eq ! ( i. intern( RcStr :: new ( "dog" ) ) , 0 ) ;
197
236
// different string gets a different #:
198
- assert_eq ! ( i. intern( @ "cat" ) , 1 ) ;
199
- assert_eq ! ( i. intern( @ "cat" ) , 1 ) ;
237
+ assert_eq ! ( i. intern( RcStr :: new ( "cat" ) ) , 1 ) ;
238
+ assert_eq ! ( i. intern( RcStr :: new ( "cat" ) ) , 1 ) ;
200
239
// dog is still at zero
201
- assert_eq ! ( i. intern( @ "dog" ) , 0 ) ;
240
+ assert_eq ! ( i. intern( RcStr :: new ( "dog" ) ) , 0 ) ;
202
241
// gensym gets 3
203
- assert_eq ! ( i. gensym( @ "zebra" ) , 2 ) ;
242
+ assert_eq ! ( i. gensym( RcStr :: new ( "zebra" ) ) , 2 ) ;
204
243
// gensym of same string gets new number :
205
- assert_eq ! ( i. gensym ( @ "zebra" ) , 3 ) ;
244
+ assert_eq ! ( i. gensym ( RcStr :: new ( "zebra" ) ) , 3 ) ;
206
245
// gensym of *existing* string gets new number:
207
- assert_eq ! ( i. gensym( @ "dog" ) , 4 ) ;
208
- assert_eq ! ( i. get( 0 ) , @ "dog" ) ;
209
- assert_eq ! ( i. get( 1 ) , @ "cat" ) ;
210
- assert_eq ! ( i. get( 2 ) , @ "zebra" ) ;
211
- assert_eq ! ( i. get( 3 ) , @ "zebra" ) ;
212
- assert_eq ! ( i. get( 4 ) , @ "dog" ) ;
246
+ assert_eq ! ( i. gensym( RcStr :: new ( "dog" ) ) , 4 ) ;
247
+ assert_eq ! ( i. get( 0 ) , RcStr :: new ( "dog" ) ) ;
248
+ assert_eq ! ( i. get( 1 ) , RcStr :: new ( "cat" ) ) ;
249
+ assert_eq ! ( i. get( 2 ) , RcStr :: new ( "zebra" ) ) ;
250
+ assert_eq ! ( i. get( 3 ) , RcStr :: new ( "zebra" ) ) ;
251
+ assert_eq ! ( i. get( 4 ) , RcStr :: new ( "dog" ) ) ;
213
252
}
214
253
215
254
#[ test]
216
255
fn i3 ( ) {
217
- let i : Interner < @str > = Interner :: prefill ( [ @"Alan ", @"Bob ", @"Carol "] ) ;
218
- assert_eq ! ( i. get( 0 ) , @"Alan" ) ;
219
- assert_eq ! ( i. get( 1 ) , @"Bob" ) ;
220
- assert_eq ! ( i. get( 2 ) , @"Carol" ) ;
221
- assert_eq ! ( i. intern( @"Bob" ) , 1 ) ;
256
+ let i : Interner < @~str > = Interner :: prefill ( [
257
+ RcStr :: new ( "Alan" ) ,
258
+ RcStr :: new ( "Bob" ) ,
259
+ RcStr :: new ( "Carol" )
260
+ ] ) ;
261
+ assert_eq ! ( i. get( 0 ) , RcStr :: new( "Alan" ) ) ;
262
+ assert_eq ! ( i. get( 1 ) , RcStr :: new( "Bob" ) ) ;
263
+ assert_eq ! ( i. get( 2 ) , RcStr :: new( "Carol" ) ) ;
264
+ assert_eq ! ( i. intern( RcStr :: new( "Bob" ) ) , 1 ) ;
222
265
}
223
266
224
267
#[ test]
@@ -241,13 +284,13 @@ mod tests {
241
284
assert_eq ! ( i. gensym( "dog" ) , 4 ) ;
242
285
// gensym tests again with gensym_copy:
243
286
assert_eq ! ( i. gensym_copy( 2 ) , 5 ) ;
244
- assert_eq ! ( i. get( 5 ) , @ "zebra" ) ;
287
+ assert_eq ! ( i. get( 5 ) , RcStr :: new ( "zebra" ) ) ;
245
288
assert_eq ! ( i. gensym_copy( 2 ) , 6 ) ;
246
- assert_eq ! ( i. get( 6 ) , @ "zebra" ) ;
247
- assert_eq ! ( i. get( 0 ) , @ "dog" ) ;
248
- assert_eq ! ( i. get( 1 ) , @ "cat" ) ;
249
- assert_eq ! ( i. get( 2 ) , @ "zebra" ) ;
250
- assert_eq ! ( i. get( 3 ) , @ "zebra" ) ;
251
- assert_eq ! ( i. get( 4 ) , @ "dog" ) ;
289
+ assert_eq ! ( i. get( 6 ) , RcStr :: new ( "zebra" ) ) ;
290
+ assert_eq ! ( i. get( 0 ) , RcStr :: new ( "dog" ) ) ;
291
+ assert_eq ! ( i. get( 1 ) , RcStr :: new ( "cat" ) ) ;
292
+ assert_eq ! ( i. get( 2 ) , RcStr :: new ( "zebra" ) ) ;
293
+ assert_eq ! ( i. get( 3 ) , RcStr :: new ( "zebra" ) ) ;
294
+ assert_eq ! ( i. get( 4 ) , RcStr :: new ( "dog" ) ) ;
252
295
}
253
296
}
0 commit comments