@@ -3,15 +3,126 @@ use std::sync::atomic::{AtomicUsize, Ordering};
3
3
use std:: sync:: { Arc , Mutex } ;
4
4
5
5
use crate :: error:: { Error , ErrorKind } ;
6
- use crate :: value:: { Enumerator , Object , Value } ;
6
+ use crate :: value:: { Enumerator , Object , Value , ValueIter } ;
7
7
use crate :: vm:: state:: State ;
8
8
9
+ pub ( crate ) struct LoopState {
10
+ pub ( crate ) with_loop_var : bool ,
11
+ pub ( crate ) recurse_jump_target : Option < usize > ,
12
+
13
+ // if we're popping the frame, do we want to jump somewhere? The
14
+ // first item is the target jump instruction, the second argument
15
+ // tells us if we need to end capturing.
16
+ pub ( crate ) current_recursion_jump : Option < ( usize , bool ) > ,
17
+
18
+ // Depending on if adjacent_loop_items is enabled or not, the iterator
19
+ // is stored either on the loop state or in the loop object. This is
20
+ // done because when the feature is disabled, we can avoid using a mutex.
21
+ pub ( crate ) object : Arc < Loop > ,
22
+ #[ cfg( not( feature = "adjacent_loop_items" ) ) ]
23
+ iter : crate :: value:: ValueIter ,
24
+ }
25
+
26
+ impl LoopState {
27
+ pub fn new (
28
+ iter : ValueIter ,
29
+ depth : usize ,
30
+ with_loop_var : bool ,
31
+ recurse_jump_target : Option < usize > ,
32
+ current_recursion_jump : Option < ( usize , bool ) > ,
33
+ ) -> LoopState {
34
+ // for an iterator where the lower and upper bound are matching we can
35
+ // consider them to have ExactSizeIterator semantics. We do however not
36
+ // expect ExactSizeIterator bounds themselves to support iteration by
37
+ // other means.
38
+ let len = match iter. size_hint ( ) {
39
+ ( lower, Some ( upper) ) if lower == upper => Some ( lower) ,
40
+ _ => None ,
41
+ } ;
42
+ LoopState {
43
+ with_loop_var,
44
+ recurse_jump_target,
45
+ current_recursion_jump,
46
+ object : Arc :: new ( Loop {
47
+ idx : AtomicUsize :: new ( !0usize ) ,
48
+ len,
49
+ depth,
50
+ #[ cfg( feature = "adjacent_loop_items" ) ]
51
+ iter : Mutex :: new ( AdjacentLoopItemIterWrapper :: new ( iter) ) ,
52
+ last_changed_value : Mutex :: default ( ) ,
53
+ } ) ,
54
+ #[ cfg( not( feature = "adjacent_loop_items" ) ) ]
55
+ iter,
56
+ }
57
+ }
58
+
59
+ pub fn did_not_iterate ( & self ) -> bool {
60
+ self . object . idx . load ( Ordering :: Relaxed ) == 0
61
+ }
62
+
63
+ pub fn next ( & mut self ) -> Option < Value > {
64
+ self . object . idx . fetch_add ( 1 , Ordering :: Relaxed ) ;
65
+ #[ cfg( feature = "adjacent_loop_items" ) ]
66
+ {
67
+ self . object . iter . lock ( ) . unwrap ( ) . next ( )
68
+ }
69
+ #[ cfg( not( feature = "adjacent_loop_items" ) ) ]
70
+ {
71
+ self . iter . next ( )
72
+ }
73
+ }
74
+ }
75
+
76
+ #[ cfg( feature = "adjacent_loop_items" ) ]
77
+ pub ( crate ) struct AdjacentLoopItemIterWrapper {
78
+ prev_item : Option < Value > ,
79
+ current_item : Option < Value > ,
80
+ next_item : Option < Value > ,
81
+ iter : ValueIter ,
82
+ }
83
+
84
+ #[ cfg( feature = "adjacent_loop_items" ) ]
85
+ impl AdjacentLoopItemIterWrapper {
86
+ pub fn new ( iterator : ValueIter ) -> AdjacentLoopItemIterWrapper {
87
+ AdjacentLoopItemIterWrapper {
88
+ prev_item : None ,
89
+ current_item : None ,
90
+ next_item : None ,
91
+ iter : iterator,
92
+ }
93
+ }
94
+
95
+ pub fn next ( & mut self ) -> Option < Value > {
96
+ self . prev_item = self . current_item . take ( ) ;
97
+ self . current_item = if let Some ( ref next) = self . next_item . take ( ) {
98
+ Some ( next. clone ( ) )
99
+ } else {
100
+ self . next_item = None ;
101
+ self . iter . next ( )
102
+ } ;
103
+ self . current_item . clone ( )
104
+ }
105
+
106
+ pub fn next_item ( & mut self ) -> Value {
107
+ if let Some ( ref next) = self . next_item {
108
+ next. clone ( )
109
+ } else {
110
+ self . next_item = self . iter . next ( ) ;
111
+ self . next_item . clone ( ) . unwrap_or_default ( )
112
+ }
113
+ }
114
+
115
+ pub fn prev_item ( & self ) -> Value {
116
+ self . prev_item . clone ( ) . unwrap_or_default ( )
117
+ }
118
+ }
119
+
9
120
pub ( crate ) struct Loop {
10
121
pub len : Option < usize > ,
11
122
pub idx : AtomicUsize ,
12
123
pub depth : usize ,
13
124
#[ cfg( feature = "adjacent_loop_items" ) ]
14
- pub value_triple : Mutex < ( Option < Value > , Option < Value > , Option < Value > ) > ,
125
+ pub iter : Mutex < AdjacentLoopItemIterWrapper > ,
15
126
pub last_changed_value : Mutex < Option < Vec < Value > > > ,
16
127
}
17
128
@@ -107,23 +218,9 @@ impl Object for Loop {
107
218
"depth" => Some ( Value :: from ( self . depth + 1 ) ) ,
108
219
"depth0" => Some ( Value :: from ( self . depth ) ) ,
109
220
#[ cfg( feature = "adjacent_loop_items" ) ]
110
- "previtem" => Some (
111
- self . value_triple
112
- . lock ( )
113
- . unwrap ( )
114
- . 0
115
- . clone ( )
116
- . unwrap_or ( Value :: UNDEFINED ) ,
117
- ) ,
221
+ "previtem" => Some ( self . iter . lock ( ) . unwrap ( ) . prev_item ( ) ) ,
118
222
#[ cfg( feature = "adjacent_loop_items" ) ]
119
- "nextitem" => Some (
120
- self . value_triple
121
- . lock ( )
122
- . unwrap ( )
123
- . 2
124
- . clone ( )
125
- . unwrap_or ( Value :: UNDEFINED ) ,
126
- ) ,
223
+ "nextitem" => Some ( self . iter . lock ( ) . unwrap ( ) . next_item ( ) ) ,
127
224
_ => None ,
128
225
}
129
226
}
0 commit comments