41
41
package com .oracle .graal .python .builtins .objects .common ;
42
42
43
43
import java .util .ArrayList ;
44
+ import java .util .Iterator ;
45
+ import java .util .NoSuchElementException ;
46
+ import java .util .function .Predicate ;
44
47
48
+ import com .oracle .graal .python .builtins .objects .PNone ;
45
49
import com .oracle .graal .python .runtime .sequence .storage .MroSequenceStorage ;
46
50
import com .oracle .truffle .api .CompilerDirectives .TruffleBoundary ;
47
51
import com .oracle .truffle .api .object .DynamicObject ;
@@ -105,17 +109,20 @@ public boolean remove(Object key, Equivalence eq) {
105
109
return result ;
106
110
}
107
111
112
+ protected Iterable <Object > getKeysIterable () {
113
+ return store .getShape ().getKeys ();
114
+ }
115
+
108
116
@ Override
109
117
public Iterable <Object > keys () {
110
- return wrapJavaIterable (store . getShape (). getKeys ());
118
+ return wrapJavaIterable (getKeysIterable ());
111
119
}
112
120
113
121
@ Override
114
122
@ TruffleBoundary
115
123
public Iterable <Object > values () {
116
124
ArrayList <Object > entries = new ArrayList <>(store .size ());
117
- Shape shape = store .getShape ();
118
- for (Object key : shape .getKeys ()) {
125
+ for (Object key : getKeysIterable ()) {
119
126
entries .add (store .get (key ));
120
127
}
121
128
return wrapJavaIterable (entries );
@@ -125,8 +132,7 @@ public Iterable<Object> values() {
125
132
@ TruffleBoundary
126
133
public Iterable <DictEntry > entries () {
127
134
ArrayList <DictEntry > entries = new ArrayList <>(store .size ());
128
- Shape shape = store .getShape ();
129
- for (Object key : shape .getKeys ()) {
135
+ for (Object key : getKeysIterable ()) {
130
136
entries .add (new DictEntry (key , store .get (key )));
131
137
}
132
138
return wrapJavaIterable (entries );
@@ -143,6 +149,67 @@ public DynamicObject getStore() {
143
149
return store ;
144
150
}
145
151
152
+
153
+ private static class FilterIterator <T > implements Iterator <T > {
154
+ private final Iterator <T > iterator ;
155
+ private final Predicate <T > predicate ;
156
+ private T value ;
157
+ private boolean valueIsSet = false ;
158
+
159
+ private FilterIterator (Iterator <T > iterator , Predicate <T > predicate ) {
160
+ this .iterator = iterator ;
161
+ this .predicate = predicate ;
162
+ }
163
+
164
+ @ Override
165
+ public boolean hasNext () {
166
+ return valueIsSet || consumeUntilNext ();
167
+ }
168
+
169
+ @ Override
170
+ public T next () {
171
+ if (valueIsSet || consumeUntilNext ()) {
172
+ valueIsSet = false ;
173
+ return value ;
174
+ }
175
+ // no more vals matching were found
176
+ throw new NoSuchElementException ();
177
+ }
178
+
179
+ private boolean consumeUntilNext () {
180
+ while (iterator .hasNext ()) {
181
+ T next = iterator .next ();
182
+ if (predicate .test (next )) {
183
+ value = next ;
184
+ valueIsSet = true ;
185
+ return true ;
186
+ }
187
+ }
188
+ return false ;
189
+ }
190
+ }
191
+
192
+ private static class NoValuePredicate <T > implements Predicate <T > {
193
+
194
+ private final DynamicObject store ;
195
+
196
+ private NoValuePredicate (DynamicObject store ) {
197
+ this .store = store ;
198
+ }
199
+
200
+ @ Override
201
+ public boolean test (T t ) {
202
+ return store .get (t ) != PNone .NO_VALUE ;
203
+ }
204
+ }
205
+
206
+ private static class NoValueFilterIterator extends FilterIterator <Object > {
207
+
208
+ private NoValueFilterIterator (DynamicObject store ) {
209
+ super (store .getShape ().getKeys ().iterator (), new NoValuePredicate <>(store ));
210
+ }
211
+ }
212
+
146
213
public static final class FastDictStorage extends DynamicObjectStorage {
147
214
public FastDictStorage () {
148
215
}
@@ -159,10 +226,60 @@ public HashingStorage copy(Equivalence eq) {
159
226
}
160
227
161
228
public static final class PythonObjectDictStorage extends DynamicObjectStorage {
229
+ private int size = -1 ;
230
+
162
231
public PythonObjectDictStorage (DynamicObject store ) {
163
232
super (store );
164
233
}
165
234
235
+ @ Override
236
+ protected Iterable <Object > getKeysIterable () {
237
+ return new Iterable <Object >() {
238
+ @ Override
239
+ public Iterator <Object > iterator () {
240
+ return new NoValueFilterIterator (getStore ());
241
+ }
242
+ };
243
+ }
244
+
245
+ @ Override
246
+ public int length () {
247
+ if (size == -1 ) {
248
+ size = 0 ;
249
+ for (Object ignored : getKeysIterable ()) {
250
+ size += 1 ;
251
+ }
252
+ }
253
+ return size ;
254
+ }
255
+
256
+ @ Override
257
+ public void setItem (Object key , Object value , Equivalence eq ) {
258
+ super .setItem (key , value , eq );
259
+ if (value != PNone .NO_VALUE ) {
260
+ size += 1 ;
261
+ }
262
+ }
263
+
264
+ @ Override
265
+ public boolean remove (Object key , Equivalence eq ) {
266
+ if (getStore ().get (key ) != PNone .NO_VALUE ) {
267
+ size -= 1 ;
268
+ }
269
+ return super .remove (key , eq );
270
+ }
271
+
272
+ @ Override
273
+ public void clear () {
274
+ super .clear ();
275
+ size = 0 ;
276
+ }
277
+
278
+ @ Override
279
+ public boolean hasKey (Object key , Equivalence eq ) {
280
+ return super .hasKey (key , eq ) && getStore ().get (key , PNone .NO_VALUE ) != PNone .NO_VALUE ;
281
+ }
282
+
166
283
@ Override
167
284
@ TruffleBoundary
168
285
public HashingStorage copy (Equivalence eq ) {
0 commit comments