Skip to content

Commit 8fe0061

Browse files
committed
implemented reversed for dict and dictviews
1 parent f53e228 commit 8fe0061

21 files changed

+357
-54
lines changed

graalpython/com.oracle.graal.python.test/src/tests/test_dict.py

Lines changed: 7 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -710,7 +710,13 @@ def test_wrapped_string_get():
710710
a = 'test'
711711
dict = locals()
712712
assert dict['a']
713-
713+
714+
@unittest.skipIf(sys.implementation.name == 'cpython' and sys.version_info[0:2] < (3, 8), "skipping for cPython versions < 3.8")
715+
def test_reverse_locals():
716+
a = 'atest'
717+
b = 'btest'
718+
dict = locals()
719+
assert list(reversed(dict)) == ['b', 'a']
714720

715721
def test_concat():
716722
r = {**{}}

graalpython/com.oracle.graal.python.test/src/tests/unittest_tags/test_dict.txt

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -33,8 +33,10 @@
3333
*graalpython.lib-python.3.test.test_dict.DictTest.test_mutating_iteration
3434
*graalpython.lib-python.3.test.test_dict.DictTest.test_mutating_lookup
3535
*graalpython.lib-python.3.test.test_dict.DictTest.test_object_set_item_single_instance_non_str_key
36+
*graalpython.lib-python.3.test.test_dict.DictTest.test_pop
3637
*graalpython.lib-python.3.test.test_dict.DictTest.test_reentrant_insertion
3738
*graalpython.lib-python.3.test.test_dict.DictTest.test_repr
39+
*graalpython.lib-python.3.test.test_dict.DictTest.test_repr_deep
3840
*graalpython.lib-python.3.test.test_dict.DictTest.test_resize1
3941
*graalpython.lib-python.3.test.test_dict.DictTest.test_resize2
4042
*graalpython.lib-python.3.test.test_dict.DictTest.test_setdefault

graalpython/com.oracle.graal.python/src/com/oracle/graal/python/builtins/PythonBuiltinClassType.java

Lines changed: 4 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -69,11 +69,14 @@ public enum PythonBuiltinClassType implements LazyPythonClass {
6969
PCell("cell"),
7070
PComplex("complex", BuiltinNames.BUILTINS),
7171
PDict("dict", BuiltinNames.BUILTINS),
72-
PDictKeysView(BuiltinNames.DICT_KEYS),
7372
PDictItemIterator(BuiltinNames.DICT_ITEMITERATOR),
73+
PDictReverseItemIterator(BuiltinNames.DICT_REVERSE_ITEMITERATOR),
7474
PDictItemsView(BuiltinNames.DICT_ITEMS),
7575
PDictKeyIterator(BuiltinNames.DICT_KEYITERATOR),
76+
PDictReverseKeyIterator(BuiltinNames.DICT_REVERSE_KEYITERATOR),
77+
PDictKeysView(BuiltinNames.DICT_KEYS),
7678
PDictValueIterator(BuiltinNames.DICT_VALUEITERATOR),
79+
PDictReverseValueIterator(BuiltinNames.DICT_REVERSE_VALUEITERATOR),
7780
PDictValuesView(BuiltinNames.DICT_VALUES),
7881
PEllipsis("ellipsis"),
7982
PEnumerate("enumerate", BuiltinNames.BUILTINS),

graalpython/com.oracle.graal.python/src/com/oracle/graal/python/builtins/objects/common/DynamicObjectStorage.java

Lines changed: 58 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -72,6 +72,7 @@
7272
import com.oracle.truffle.api.object.Shape;
7373
import com.oracle.truffle.api.profiles.BranchProfile;
7474
import com.oracle.truffle.api.profiles.ConditionProfile;
75+
import java.util.List;
7576

7677
/**
7778
* This storage keeps a reference to the MRO when used for a type dict. Writing to this storage will
@@ -358,22 +359,31 @@ public HashingStorageIterable<Object> keys(
358359
return new HashingStorageIterable<>(new KeysIterator(store, readNode));
359360
}
360361

361-
private static final class KeysIterator implements Iterator<Object> {
362-
private final Iterator<Object> keyIter;
362+
@ExportMessage
363+
public HashingStorageIterable<Object> reverseKeys(
364+
@Exclusive @Cached ReadAttributeFromDynamicObjectNode readNode) {
365+
return new HashingStorageIterable<>(new ReverseKeysIterator(store, readNode));
366+
}
367+
368+
private abstract static class AbstractKeysIterator implements Iterator<Object> {
363369
private final DynamicObject store;
364370
private final ReadAttributeFromDynamicObjectNode readNode;
365371
private Object next = null;
366372

367-
public KeysIterator(DynamicObject store, ReadAttributeFromDynamicObjectNode readNode) {
368-
this.keyIter = store.getShape().getKeys().iterator();
373+
public AbstractKeysIterator(DynamicObject store, ReadAttributeFromDynamicObjectNode readNode) {
369374
this.store = store;
370375
this.readNode = readNode;
371376
}
372377

378+
protected abstract boolean hasNextKey();
379+
380+
protected abstract Object nextKey();
381+
373382
@TruffleBoundary
383+
@Override
374384
public boolean hasNext() {
375-
while (next == null && keyIter.hasNext()) {
376-
Object key = keyIter.next();
385+
while (next == null && hasNextKey()) {
386+
Object key = nextKey();
377387
Object value = readNode.execute(store, key);
378388
if (value != PNone.NO_VALUE) {
379389
next = key;
@@ -382,6 +392,7 @@ public boolean hasNext() {
382392
return next != null;
383393
}
384394

395+
@Override
385396
public Object next() {
386397
hasNext(); // find the next value
387398
if (next != null) {
@@ -394,6 +405,47 @@ public Object next() {
394405
}
395406
}
396407

408+
private static final class KeysIterator extends AbstractKeysIterator {
409+
private final Iterator<Object> keyIter;
410+
411+
public KeysIterator(DynamicObject store, ReadAttributeFromDynamicObjectNode readNode) {
412+
super(store, readNode);
413+
this.keyIter = store.getShape().getKeys().iterator();
414+
}
415+
416+
@Override
417+
protected boolean hasNextKey() {
418+
return keyIter.hasNext();
419+
}
420+
421+
@Override
422+
protected Object nextKey() {
423+
return keyIter.next();
424+
}
425+
}
426+
427+
private static final class ReverseKeysIterator extends AbstractKeysIterator {
428+
private final List<Object> keyList;
429+
private int index;
430+
431+
public ReverseKeysIterator(DynamicObject store, ReadAttributeFromDynamicObjectNode readNode) {
432+
super(store, readNode);
433+
this.keyList = store.getShape().getKeyList();
434+
this.index = keyList.size() - 1;
435+
}
436+
437+
@Override
438+
protected boolean hasNextKey() {
439+
return index >= 0;
440+
}
441+
442+
@Override
443+
protected Object nextKey() {
444+
return keyList.get(index--);
445+
}
446+
447+
}
448+
397449
@ExportMessage
398450
public HashingStorageIterable<DictEntry> entries(
399451
@Exclusive @Cached ReadAttributeFromDynamicObjectNode readNode) {

graalpython/com.oracle.graal.python/src/com/oracle/graal/python/builtins/objects/common/EconomicMapStorage.java

Lines changed: 6 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -574,6 +574,12 @@ public HashingStorageIterable<Object> keys() {
574574
return new HashingStorageIterable<>(new KeysIterator(map.getKeys().iterator()));
575575
}
576576

577+
@Override
578+
@ExportMessage
579+
public HashingStorageIterable<Object> reverseKeys() {
580+
return new HashingStorageIterable<>(new KeysIterator(map.reverseKeyIterator()));
581+
}
582+
577583
private static final class KeysIterator implements Iterator<Object> {
578584
private final Iterator<DictKey> keysIterator;
579585

graalpython/com.oracle.graal.python/src/com/oracle/graal/python/builtins/objects/common/EmptyStorage.java

Lines changed: 9 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -118,10 +118,12 @@ public HashingStorage copy() {
118118
}
119119

120120
private static final Iterator<Object> KEYS_ITERATOR = new Iterator<Object>() {
121+
@Override
121122
public boolean hasNext() {
122123
return false;
123124
}
124125

126+
@Override
125127
public Object next() {
126128
throw new NoSuchElementException();
127129
}
@@ -132,4 +134,11 @@ public Object next() {
132134
public HashingStorageIterable<Object> keys() {
133135
return new HashingStorageIterable<>(KEYS_ITERATOR);
134136
}
137+
138+
@ExportMessage
139+
@Override
140+
public HashingStorageIterable<Object> reverseKeys() {
141+
return new HashingStorageIterable<>(KEYS_ITERATOR);
142+
}
143+
135144
}

graalpython/com.oracle.graal.python/src/com/oracle/graal/python/builtins/objects/common/HashingStorage.java

Lines changed: 23 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -276,6 +276,12 @@ HashingStorageIterable<Object> keys() {
276276
throw new AbstractMethodError("HashingStorage.keys");
277277
}
278278

279+
@ExportMessage
280+
public HashingStorageIterable<Object> reverseKeys() {
281+
CompilerDirectives.transferToInterpreterAndInvalidate();
282+
throw new AbstractMethodError("HashingStorage.reverseKeys");
283+
}
284+
279285
@GenerateUncached
280286
protected abstract static class AddToOtherInjectNode extends InjectIntoNode {
281287
@Specialization
@@ -542,14 +548,19 @@ public HashingStorage diff(HashingStorage other,
542548

543549
@ExportMessage
544550
public HashingStorageIterable<Object> values(@CachedLibrary("this") HashingStorageLibrary lib) {
545-
return new HashingStorageIterable<>(new ValuesIterator(this, lib));
551+
return new HashingStorageIterable<>(new ValuesIterator(this, lib.keys(this).iterator(), lib));
552+
}
553+
554+
@ExportMessage
555+
public HashingStorageIterable<Object> reverseValues(@CachedLibrary("this") HashingStorageLibrary lib) {
556+
return new HashingStorageIterable<>(new ValuesIterator(this, lib.reverseKeys(this).iterator(), lib));
546557
}
547558

548559
private static final class ValuesIterator implements Iterator<Object> {
549560
private final Iterator<DictEntry> entriesIterator;
550561

551-
ValuesIterator(HashingStorage self, HashingStorageLibrary lib) {
552-
this.entriesIterator = new EntriesIterator(self, lib);
562+
ValuesIterator(HashingStorage self, HashingStorageIterator<Object> keysIterator, HashingStorageLibrary lib) {
563+
this.entriesIterator = new EntriesIterator(self, keysIterator, lib);
553564
}
554565

555566
@Override
@@ -564,19 +575,24 @@ public Object next() {
564575
}
565576

566577
@ExportMessage
567-
public HashingStorageIterable<DictEntry> entries(@CachedLibrary("this") HashingStorageLibrary lib) {
568-
return new HashingStorageIterable<>(new EntriesIterator(this, lib));
578+
public final HashingStorageIterable<DictEntry> entries(@CachedLibrary("this") HashingStorageLibrary lib) {
579+
return new HashingStorageIterable<>(new EntriesIterator(this, lib.keys(this).iterator(), lib));
580+
}
581+
582+
@ExportMessage
583+
public final HashingStorageIterable<DictEntry> reverseEntries(@CachedLibrary("this") HashingStorageLibrary lib) {
584+
return new HashingStorageIterable<>(new EntriesIterator(this, lib.reverseKeys(this).iterator(), lib));
569585
}
570586

571587
private static final class EntriesIterator implements Iterator<DictEntry> {
572588
private final HashingStorageIterator<Object> keysIterator;
573589
private final HashingStorage self;
574590
private final HashingStorageLibrary lib;
575591

576-
EntriesIterator(HashingStorage self, HashingStorageLibrary lib) {
592+
EntriesIterator(HashingStorage self, HashingStorageIterator<Object> keysIterator, HashingStorageLibrary lib) {
577593
this.self = self;
578594
this.lib = lib;
579-
this.keysIterator = lib.keys(self).iterator();
595+
this.keysIterator = keysIterator;
580596
}
581597

582598
@Override

graalpython/com.oracle.graal.python/src/com/oracle/graal/python/builtins/objects/common/HashingStorageLibrary.java

Lines changed: 30 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -496,14 +496,32 @@ public T next() {
496496
public abstract HashingStorageIterable<Object> keys(HashingStorage self);
497497

498498
/**
499-
* This method can be used to iterate over the values of a store. Due to the nature of Java
500-
* iterators being an interface and the different storage strategies, this may be slow and
501-
* should be used with caution.
499+
* This method can be used to iterate over the keys of a store in a reversed order. Due to the
500+
* nature of Java iterators being an interface and the different storage strategies, this may be
501+
* slow and should be used with caution.
502+
*
503+
* @return an iterator over the keys in this store.
504+
*/
505+
public abstract HashingStorageIterable<Object> reverseKeys(HashingStorage self);
506+
507+
/**
508+
* This method can be used to iterate over the values of a store in a reversed order. Due to the
509+
* nature of Java iterators being an interface and the different storage strategies, this may be
510+
* slow and should be used with caution.
502511
*
503512
* @return an iterator over the values in this store.
504513
*/
505514
public abstract HashingStorageIterable<Object> values(HashingStorage self);
506515

516+
/**
517+
* This method can be used to iterate over the values of a store in a reversed order. Due to the
518+
* nature of Java iterators being an interface and the different storage strategies, this may be
519+
* slow and should be used with caution.
520+
*
521+
* @return an iterator over the values in this store.
522+
*/
523+
public abstract HashingStorageIterable<Object> reverseValues(HashingStorage self);
524+
507525
/**
508526
* This method can be used to iterate over the key-value pairs of a store. Due to the nature of
509527
* Java iterators being an interface and the different storage strategies, this may be slow and
@@ -513,6 +531,15 @@ public T next() {
513531
*/
514532
public abstract HashingStorageIterable<HashingStorage.DictEntry> entries(HashingStorage self);
515533

534+
/**
535+
* This method can be used to iterate over the key-value pairs of a store. Due to the nature of
536+
* Java iterators being an interface and the different storage strategies, this may be slow and
537+
* should be used with caution.
538+
*
539+
* @return an iterator over the keys-value pairs in this store.
540+
*/
541+
public abstract HashingStorageIterable<HashingStorage.DictEntry> reverseEntries(HashingStorage self);
542+
516543
static final LibraryFactory<HashingStorageLibrary> FACTORY = LibraryFactory.resolve(HashingStorageLibrary.class);
517544

518545
public static LibraryFactory<HashingStorageLibrary> getFactory() {

graalpython/com.oracle.graal.python/src/com/oracle/graal/python/builtins/objects/common/KeywordsStorage.java

Lines changed: 45 additions & 9 deletions
Original file line numberDiff line numberDiff line change
@@ -278,30 +278,66 @@ public HashingStorageIterable<Object> keys() {
278278
return new HashingStorageIterable<>(new KeysIterator(this));
279279
}
280280

281-
private static final class KeysIterator implements Iterator<Object> {
282-
private final KeywordsStorage storage;
283-
private int index;
281+
@ExportMessage
282+
@Override
283+
public HashingStorageIterable<Object> reverseKeys() {
284+
return new HashingStorageIterable<>(new ReverseKeysIterator(this));
285+
}
284286

285-
public KeysIterator(KeywordsStorage keywordsStorage) {
286-
this.index = 0;
287+
private abstract static class AbstractKeysIterator implements Iterator<Object> {
288+
protected final KeywordsStorage storage;
289+
protected int index;
290+
291+
public AbstractKeysIterator(KeywordsStorage keywordsStorage, int initialIndex) {
292+
this.index = initialIndex;
287293
this.storage = keywordsStorage;
288294
}
289295

290-
public boolean hasNext() {
291-
return index < storage.length();
292-
}
296+
public abstract void nextIndex();
293297

294298
public Object next() {
295299
if (hasNext()) {
296300
Object result = storage.keywords[index].getName();
297-
index += 1;
301+
nextIndex();
298302
return result;
299303
} else {
300304
throw new NoSuchElementException();
301305
}
302306
}
303307
}
304308

309+
private static final class KeysIterator extends AbstractKeysIterator {
310+
public KeysIterator(KeywordsStorage keywordsStorage) {
311+
super(keywordsStorage, 0);
312+
}
313+
314+
@Override
315+
public boolean hasNext() {
316+
return index < storage.length();
317+
}
318+
319+
@Override
320+
public void nextIndex() {
321+
index += 1;
322+
}
323+
}
324+
325+
private static final class ReverseKeysIterator extends AbstractKeysIterator {
326+
public ReverseKeysIterator(KeywordsStorage keywordsStorage) {
327+
super(keywordsStorage, keywordsStorage.keywords.length - 1);
328+
}
329+
330+
@Override
331+
public boolean hasNext() {
332+
return index >= 0;
333+
}
334+
335+
@Override
336+
public void nextIndex() {
337+
index -= 1;
338+
}
339+
}
340+
305341
public static KeywordsStorage create(PKeyword[] keywords) {
306342
return new KeywordsStorage(keywords);
307343
}

0 commit comments

Comments
 (0)