@@ -18,12 +18,28 @@ enum dlist_node<T> = @{
18
18
mut next: dlist_link<T >
19
19
} ;
20
20
21
- // Needs to be an @-box so nodes can back-reference it.
22
- enum dlist < T > = @{
23
- mut size: uint,
24
- mut hd: dlist_link <T >,
25
- mut tl: dlist_link<T >
26
- } ;
21
+ class dlist_root<T > {
22
+ let mut size: uint ;
23
+ let mut hd: dlist_link < T > ;
24
+ let mut tl: dlist_link < T > ;
25
+ new ( ) {
26
+ self . size = 0 ; self . hd = none; self . tl = none;
27
+ }
28
+ drop {
29
+ /* FIXME (#????) This doesn't work during task failure - the box
30
+ * annihilator might have killed some of our nodes already. This will
31
+ * be safe to uncomment when the box annihilator is safer. As is,
32
+ * this makes test_dlist_cyclic_link below crash the runtime.
33
+ // Empty the list. Not doing this explicitly would leave cyclic links
34
+ // around, not to be freed until cycle collection at task exit.
35
+ while self.hd.is_some() {
36
+ self.unlink(self.hd.get());
37
+ }
38
+ */
39
+ }
40
+ }
41
+
42
+ type dlist<T > = @dlist_root<T >;
27
43
28
44
impl private_methods < T > for dlist_node < T > {
29
45
pure fn assert_links ( ) {
@@ -91,7 +107,7 @@ pure fn new_dlist_node<T>(+data: T) -> dlist_node<T> {
91
107
92
108
/// Creates a new, empty dlist.
93
109
pure fn new_dlist < T > ( ) -> dlist < T > {
94
- dlist ( @ { mut size : 0 , mut hd : none , mut tl : none } )
110
+ @ unchecked { dlist_root ( ) }
95
111
}
96
112
97
113
/// Creates a new dlist with a single element
@@ -118,7 +134,7 @@ fn concat<T>(lists: dlist<dlist<T>>) -> dlist<T> {
118
134
result
119
135
}
120
136
121
- impl private_methods < T > for dlist < T > {
137
+ impl private_methods < T > for dlist_root < T > {
122
138
pure fn new_link ( -data : T ) -> dlist_link < T > {
123
139
some ( dlist_node ( @{ data: data, mut linked: true ,
124
140
mut prev: none, mut next: none} ) )
@@ -334,7 +350,7 @@ impl extensions<T> for dlist<T> {
334
350
* to the other list's head. O(1).
335
351
*/
336
352
fn append ( them : dlist < T > ) {
337
- if box:: ptr_eq ( * self , * them) {
353
+ if box:: ptr_eq ( self , them) {
338
354
fail ~"Cannot append a dlist to itself!"
339
355
}
340
356
if them.len() > 0 {
@@ -351,7 +367,7 @@ impl extensions<T> for dlist<T> {
351
367
* list's tail to this list's head. O(1).
352
368
*/
353
369
fn prepend(them: dlist<T>) {
354
- if box::ptr_eq(* self, * them) {
370
+ if box::ptr_eq(self, them) {
355
371
fail ~" Cannot prepend a dlist to itself!"
356
372
}
357
373
if them. len ( ) > 0 {
@@ -366,15 +382,25 @@ impl extensions<T> for dlist<T> {
366
382
367
383
/// Reverse the list's elements in place. O(n).
368
384
fn reverse ( ) {
369
- let temp = new_dlist :: < T > ( ) ;
385
+ do option:: while_some ( self . hd ) |nobe| {
386
+ let next_nobe = nobe. next ;
387
+ self . remove ( nobe) ;
388
+ self . make_mine ( nobe) ;
389
+ self . add_head ( some ( nobe) ) ;
390
+ next_nobe
391
+ }
392
+ }
393
+
394
+ /**
395
+ * Remove everything from the list. This is important because the cyclic
396
+ * links won't otherwise be automatically refcounted-collected. O(n).
397
+ */
398
+ fn clear ( ) {
399
+ // Cute as it would be to simply detach the list and proclaim "O(1)!",
400
+ // the GC would still be a hidden O(n). Better to be honest about it.
370
401
while !self . is_empty ( ) {
371
- let nobe = self . pop_n ( ) . get ( ) ;
372
- nobe. linked = true ; // meh, kind of disorganised.
373
- temp. add_head ( some ( nobe) ) ;
402
+ let _ = self . pop ( ) ;
374
403
}
375
- self . hd = temp. hd ;
376
- self . tl = temp. tl ;
377
- self . size = temp. size ;
378
404
}
379
405
380
406
/// Iterate over nodes.
@@ -847,15 +873,15 @@ mod tests {
847
873
l. assert_consistent ( ) ; assert l. is_empty ( ) ;
848
874
}
849
875
#[ test] #[ should_fail] #[ ignore( cfg( windows) ) ]
850
- fn test_asymmetric_link ( ) {
876
+ fn test_dlist_asymmetric_link ( ) {
851
877
let l = new_dlist :: < int > ( ) ;
852
878
let _one = l. push_n ( 1 ) ;
853
879
let two = l. push_n ( 2 ) ;
854
880
two. prev = none;
855
881
l. assert_consistent ( ) ;
856
882
}
857
883
#[ test] #[ should_fail] #[ ignore( cfg( windows) ) ]
858
- fn test_cyclic_list ( ) {
884
+ fn test_dlist_cyclic_list ( ) {
859
885
let l = new_dlist :: < int > ( ) ;
860
886
let one = l. push_n ( 1 ) ;
861
887
let _two = l. push_n ( 2 ) ;
@@ -865,32 +891,32 @@ mod tests {
865
891
l. assert_consistent ( ) ;
866
892
}
867
893
#[ test] #[ should_fail] #[ ignore( cfg( windows) ) ]
868
- fn test_headless ( ) {
894
+ fn test_dlist_headless ( ) {
869
895
new_dlist :: < int > ( ) . head ( ) ;
870
896
}
871
897
#[ test] #[ should_fail] #[ ignore( cfg( windows) ) ]
872
- fn test_insert_already_present_before ( ) {
898
+ fn test_dlist_insert_already_present_before ( ) {
873
899
let l = new_dlist :: < int > ( ) ;
874
900
let one = l. push_n ( 1 ) ;
875
901
let two = l. push_n ( 2 ) ;
876
902
l. insert_n_before ( two, one) ;
877
903
}
878
904
#[ test] #[ should_fail] #[ ignore( cfg( windows) ) ]
879
- fn test_insert_already_present_after ( ) {
905
+ fn test_dlist_insert_already_present_after ( ) {
880
906
let l = new_dlist :: < int > ( ) ;
881
907
let one = l. push_n ( 1 ) ;
882
908
let two = l. push_n ( 2 ) ;
883
909
l. insert_n_after ( one, two) ;
884
910
}
885
911
#[ test] #[ should_fail] #[ ignore( cfg( windows) ) ]
886
- fn test_insert_before_orphan ( ) {
912
+ fn test_dlist_insert_before_orphan ( ) {
887
913
let l = new_dlist :: < int > ( ) ;
888
914
let one = new_dlist_node ( 1 ) ;
889
915
let two = new_dlist_node ( 2 ) ;
890
916
l. insert_n_before ( one, two) ;
891
917
}
892
918
#[ test] #[ should_fail] #[ ignore( cfg( windows) ) ]
893
- fn test_insert_after_orphan ( ) {
919
+ fn test_dlist_insert_after_orphan ( ) {
894
920
let l = new_dlist :: < int > ( ) ;
895
921
let one = new_dlist_node ( 1 ) ;
896
922
let two = new_dlist_node ( 2 ) ;
0 commit comments