From 65904dd64399205df442bd2e7d36ab1090d29d11 Mon Sep 17 00:00:00 2001
From: TimAndy <xuchonglei@126.com>
Date: Wed, 10 Jul 2019 15:38:00 +0800
Subject: [PATCH] Improve reverse() performance

---
 .../com/bestvike/linq/enumerable/Reverse.java |  46 ++-
 .../com/bestvike/linq/enumerable/Select.java  | 341 +++++++++++++++++-
 .../bestvike/linq/enumerable/_Partition.java  | 315 +++++++++++++++-
 3 files changed, 694 insertions(+), 8 deletions(-)

diff --git a/src/main/java/com/bestvike/linq/enumerable/Reverse.java b/src/main/java/com/bestvike/linq/enumerable/Reverse.java
index 1fba855d..e5934b2b 100644
--- a/src/main/java/com/bestvike/linq/enumerable/Reverse.java
+++ b/src/main/java/com/bestvike/linq/enumerable/Reverse.java
@@ -1,6 +1,8 @@
 package com.bestvike.linq.enumerable;
 
+import com.bestvike.collections.generic.IArrayList;
 import com.bestvike.collections.generic.ICollection;
+import com.bestvike.collections.generic.IList;
 import com.bestvike.linq.IEnumerable;
 import com.bestvike.linq.exception.ExceptionArgument;
 import com.bestvike.linq.exception.ThrowHelper;
@@ -20,23 +22,59 @@ public static <TSource> IEnumerable<TSource> reverse(IEnumerable<TSource> source
         if (source == null)
             ThrowHelper.throwArgumentNullException(ExceptionArgument.source);
 
-        return new ReverseIterator<>(source);
+        if (source instanceof ReverseIterator) {
+            ReverseIterator<TSource> reverse = (ReverseIterator<TSource>) source;
+            return reverse._reverse();
+        }
+
+        if (source instanceof IList) {
+            if (source instanceof IArrayList) {
+                IArrayList<TSource> list = (IArrayList<TSource>) source;
+                return new ReverseListPartition<>(list, 0, Integer.MAX_VALUE);
+            }
+            IList<TSource> list = (IList<TSource>) source;
+            return new ReverseIListPartition<>(list, 0, Integer.MAX_VALUE);
+        }
+
+        return new ReverseEnumerableIterator<>(source);
     }
 }
 
 
-final class ReverseIterator<TSource> extends Iterator<TSource> implements IIListProvider<TSource> {
+abstract class ReverseIterator<TSource> extends Iterator<TSource> implements IIListProvider<TSource> {
+    public abstract IEnumerable<TSource> _reverse();
+
+    @Override
+    public abstract TSource[] _toArray(Class<TSource> clazz);
+
+    @Override
+    public abstract Object[] _toArray();
+
+    @Override
+    public abstract List<TSource> _toList();
+
+    @Override
+    public abstract int _getCount(boolean onlyIfCheap);
+}
+
+
+final class ReverseEnumerableIterator<TSource> extends ReverseIterator<TSource> {
     private final IEnumerable<TSource> source;
     private Object[] buffer;
 
-    ReverseIterator(IEnumerable<TSource> source) {
+    ReverseEnumerableIterator(IEnumerable<TSource> source) {
         assert source != null;
         this.source = source;
     }
 
     @Override
     public Iterator<TSource> clone() {
-        return new ReverseIterator<>(this.source);
+        return new ReverseEnumerableIterator<>(this.source);
+    }
+
+    @Override
+    public IEnumerable<TSource> _reverse() {
+        return this.source;
     }
 
     @Override
diff --git a/src/main/java/com/bestvike/linq/enumerable/Select.java b/src/main/java/com/bestvike/linq/enumerable/Select.java
index 0c506076..f948f5e7 100644
--- a/src/main/java/com/bestvike/linq/enumerable/Select.java
+++ b/src/main/java/com/bestvike/linq/enumerable/Select.java
@@ -1113,7 +1113,7 @@ public int _getCount(boolean onlyIfCheap) {
 
 
 @DebuggerDisplay("Count = {_getCount()}")
-final class SelectListPartitionIterator<TSource, TResult> extends Iterator<TResult> implements IPartition<TResult> {
+final class SelectListPartitionIterator<TSource, TResult> extends ReverseIterator<TResult> implements IPartition<TResult> {
     private final IArrayList<TSource> source;
     private final Func1<TSource, TResult> selector;
     private final int minIndexInclusive;
@@ -1135,6 +1135,11 @@ public Iterator<TResult> clone() {
         return new SelectListPartitionIterator<>(this.source, this.selector, this.minIndexInclusive, this.maxIndexInclusive);
     }
 
+    @Override
+    public IEnumerable<TResult> _reverse() {
+        return new SelectReverseListPartitionIterator<>(this.source, this.selector, this.minIndexInclusive, this.maxIndexInclusive);
+    }
+
     @Override
     public boolean moveNext() {
         // this.state - 1 represents the zero-based index into the list.
@@ -1273,7 +1278,7 @@ public int _getCount(boolean onlyIfCheap) {
 
 
 @DebuggerDisplay("Count = {_getCount()}")
-final class SelectIListPartitionIterator<TSource, TResult> extends Iterator<TResult> implements IPartition<TResult> {
+final class SelectIListPartitionIterator<TSource, TResult> extends ReverseIterator<TResult> implements IPartition<TResult> {
     private final IList<TSource> source;
     private final Func1<TSource, TResult> selector;
     private final int minIndexInclusive;
@@ -1326,6 +1331,12 @@ public Iterator<TResult> clone() {
         return new SelectIListPartitionIterator<>(this.source, this.selector, this.minIndexInclusive, this.maxIndexInclusive);
     }
 
+    //see EnumerablePartition
+    @Override
+    public IEnumerable<TResult> _reverse() {
+        return new SelectReverseIListPartitionIterator<>(this.source, this.selector, this.minIndexInclusive, this.maxIndexInclusive);
+    }
+
     //see EnumerablePartition
     @Override
     public void close() {
@@ -1531,3 +1542,329 @@ private boolean skipBeforeFirst(IEnumerator<TSource> en) {
         return skipBefore(this.minIndexInclusive, en);
     }
 }
+
+
+final class SelectReverseListPartitionIterator<TSource, TResult> extends ReverseIterator<TResult> implements IPartition<TResult> {
+    private final IArrayList<TSource> source;
+    private final Func1<TSource, TResult> selector;
+    private final int minIndexInclusive;
+    private final int maxIndexInclusive;
+
+    SelectReverseListPartitionIterator(IArrayList<TSource> source, Func1<TSource, TResult> selector, int minIndexInclusive, int maxIndexInclusive) {
+        assert source != null;
+        assert selector != null;
+        assert minIndexInclusive >= 0;
+        assert minIndexInclusive <= maxIndexInclusive;
+        this.source = source;
+        this.selector = selector;
+        this.minIndexInclusive = minIndexInclusive;
+        this.maxIndexInclusive = maxIndexInclusive;
+    }
+
+    @Override
+    public Iterator<TResult> clone() {
+        return new SelectReverseListPartitionIterator<>(this.source, this.selector, this.minIndexInclusive, this.maxIndexInclusive);
+    }
+
+    @Override
+    public IEnumerable<TResult> _reverse() {
+        return new SelectListPartitionIterator<>(this.source, this.selector, this.minIndexInclusive, this.maxIndexInclusive);
+    }
+
+    @Override
+    public boolean moveNext() {
+        // _state - 1 represents the zero-based index into the list.
+        // Having a separate field for the index would be more readable. However, we save it
+        // into _state with a bias to minimize field size of the iterator.
+        int index = this.state - 1;
+        int count = this.source._getCount();
+        if (Integer.compareUnsigned(index, this.maxIndexInclusive - this.minIndexInclusive) <= 0 && index < count - this.minIndexInclusive) {
+            this.current = this.selector.apply(this.source.get(Math.min(count - 1, this.maxIndexInclusive) - index));
+            ++this.state;
+            return true;
+        }
+
+        this.close();
+        return false;
+    }
+
+    @Override
+    public <TResult2> IEnumerable<TResult2> _select(Func1<TResult, TResult2> selector) {
+        return new SelectReverseListPartitionIterator<>(this.source, Utilities.combineSelectors(this.selector, selector), this.minIndexInclusive, this.maxIndexInclusive);
+    }
+
+    @Override
+    public IPartition<TResult> _skip(int count) {
+        assert count > 0;
+        int maxIndex = Math.min(this.source._getCount() - 1, this.maxIndexInclusive) - count;
+        return maxIndex < this.minIndexInclusive ? EmptyPartition.instance() : new SelectReverseListPartitionIterator<>(this.source, this.selector, this.minIndexInclusive, maxIndex);
+    }
+
+    @Override
+    public IPartition<TResult> _take(int count) {
+        assert count > 0;
+        int minIndex = Math.min(this.source._getCount() - 1, this.maxIndexInclusive) - count + 1;
+        return minIndex <= this.minIndexInclusive ? this : new SelectReverseListPartitionIterator<>(this.source, this.selector, minIndex, this.maxIndexInclusive);
+    }
+
+    @Override
+    public TResult _tryGetElementAt(int index, out<Boolean> found) {
+        int count = this.source._getCount();
+        if (Integer.compareUnsigned(index, this.maxIndexInclusive - this.minIndexInclusive) <= 0 && index < count - this.minIndexInclusive) {
+            found.value = true;
+            return this.selector.apply(this.source.get(Math.min(count - 1, this.maxIndexInclusive) - index));
+        }
+
+        found.value = false;
+        return null;
+    }
+
+    @Override
+    public TResult _tryGetFirst(out<Boolean> found) {
+        int lastIndex = this.source._getCount() - 1;
+        if (lastIndex >= this.minIndexInclusive) {
+            found.value = true;
+            return this.selector.apply(this.source.get(Math.min(lastIndex, this.maxIndexInclusive)));
+        }
+
+        found.value = false;
+        return null;
+    }
+
+    @Override
+    public TResult _tryGetLast(out<Boolean> found) {
+        if (this.source._getCount() > this.minIndexInclusive) {
+            found.value = true;
+            return this.selector.apply(this.source.get(this.minIndexInclusive));
+        }
+
+        found.value = false;
+        return null;
+    }
+
+    private int getCount() {
+        int count = this.source._getCount();
+        if (count <= this.minIndexInclusive)
+            return 0;
+
+        return Math.min(count - 1, this.maxIndexInclusive) - this.minIndexInclusive + 1;
+    }
+
+    @Override
+    public TResult[] _toArray(Class<TResult> clazz) {
+        int count = this.getCount();
+        if (count == 0)
+            return ArrayUtils.empty(clazz);
+
+        TResult[] array = ArrayUtils.newInstance(clazz, count);
+        for (int i = 0, curIdx = Math.min(this.source._getCount() - 1, this.maxIndexInclusive); i != array.length; ++i, --curIdx)
+            array[i] = this.selector.apply(this.source.get(curIdx));
+
+        return array;
+    }
+
+    @Override
+    public Object[] _toArray() {
+        int count = this.getCount();
+        if (count == 0)
+            return ArrayUtils.empty();
+
+        Object[] array = new Object[count];
+        for (int i = 0, curIdx = Math.min(this.source._getCount() - 1, this.maxIndexInclusive); i != array.length; ++i, --curIdx)
+            array[i] = this.selector.apply(this.source.get(curIdx));
+
+        return array;
+    }
+
+    @Override
+    public List<TResult> _toList() {
+        int count = this.getCount();
+        if (count == 0)
+            return ListUtils.empty();
+
+        List<TResult> list = new ArrayList<>(count);
+        int end = this.minIndexInclusive - 1;
+        for (int i = Math.min(this.source._getCount() - 1, this.maxIndexInclusive); i != end; --i)
+            list.add(this.selector.apply(this.source.get(i)));
+
+        return list;
+    }
+
+    @Override
+    public int _getCount(boolean onlyIfCheap) {
+        // In case someone uses Count() to force evaluation of
+        // the selector, run it provided `onlyIfCheap` is false.
+        int count = this.getCount();
+
+        if (!onlyIfCheap) {
+            int end = this.minIndexInclusive - 1;
+            for (int i = Math.min(this.source._getCount() - 1, this.maxIndexInclusive); i != end; --i)
+                this.selector.apply(this.source.get(i));
+        }
+
+        return count;
+    }
+}
+
+
+final class SelectReverseIListPartitionIterator<TSource, TResult> extends ReverseIterator<TResult> implements IPartition<TResult> {
+    private final IList<TSource> source;
+    private final Func1<TSource, TResult> selector;
+    private final int minIndexInclusive;
+    private final int maxIndexInclusive;
+
+    SelectReverseIListPartitionIterator(IList<TSource> source, Func1<TSource, TResult> selector, int minIndexInclusive, int maxIndexInclusive) {
+        assert source != null;
+        assert selector != null;
+        assert minIndexInclusive >= 0;
+        assert minIndexInclusive <= maxIndexInclusive;
+        this.source = source;
+        this.selector = selector;
+        this.minIndexInclusive = minIndexInclusive;
+        this.maxIndexInclusive = maxIndexInclusive;
+    }
+
+    @Override
+    public Iterator<TResult> clone() {
+        return new SelectReverseIListPartitionIterator<>(this.source, this.selector, this.minIndexInclusive, this.maxIndexInclusive);
+    }
+
+    @Override
+    public IEnumerable<TResult> _reverse() {
+        return new SelectIListPartitionIterator<>(this.source, this.selector, this.minIndexInclusive, this.maxIndexInclusive);
+    }
+
+    @Override
+    public boolean moveNext() {
+        // _state - 1 represents the zero-based index into the list.
+        // Having a separate field for the index would be more readable. However, we save it
+        // into _state with a bias to minimize field size of the iterator.
+        int index = this.state - 1;
+        int count = this.source._getCount();
+        if (Integer.compareUnsigned(index, this.maxIndexInclusive - this.minIndexInclusive) <= 0 && index < count - this.minIndexInclusive) {
+            this.current = this.selector.apply(this.source.get(Math.min(count - 1, this.maxIndexInclusive) - index));
+            ++this.state;
+            return true;
+        }
+
+        this.close();
+        return false;
+    }
+
+    @Override
+    public <TResult2> IEnumerable<TResult2> _select(Func1<TResult, TResult2> selector) {
+        return new SelectReverseIListPartitionIterator<>(this.source, Utilities.combineSelectors(this.selector, selector), this.minIndexInclusive, this.maxIndexInclusive);
+    }
+
+    @Override
+    public IPartition<TResult> _skip(int count) {
+        assert count > 0;
+        int maxIndex = Math.min(this.source._getCount() - 1, this.maxIndexInclusive) - count;
+        return maxIndex < this.minIndexInclusive ? EmptyPartition.instance() : new SelectReverseIListPartitionIterator<>(this.source, this.selector, this.minIndexInclusive, maxIndex);
+    }
+
+    @Override
+    public IPartition<TResult> _take(int count) {
+        assert count > 0;
+        int minIndex = Math.min(this.source._getCount() - 1, this.maxIndexInclusive) - count + 1;
+        return minIndex <= this.minIndexInclusive ? this : new SelectReverseIListPartitionIterator<>(this.source, this.selector, minIndex, this.maxIndexInclusive);
+    }
+
+    @Override
+    public TResult _tryGetElementAt(int index, out<Boolean> found) {
+        int count = this.source._getCount();
+        if (Integer.compareUnsigned(index, this.maxIndexInclusive - this.minIndexInclusive) <= 0 && index < count - this.minIndexInclusive) {
+            found.value = true;
+            return this.selector.apply(this.source.get(Math.min(count - 1, this.maxIndexInclusive) - index));
+        }
+
+        found.value = false;
+        return null;
+    }
+
+    @Override
+    public TResult _tryGetFirst(out<Boolean> found) {
+        int lastIndex = this.source._getCount() - 1;
+        if (lastIndex >= this.minIndexInclusive) {
+            found.value = true;
+            return this.selector.apply(this.source.get(Math.min(lastIndex, this.maxIndexInclusive)));
+        }
+
+        found.value = false;
+        return null;
+    }
+
+    @Override
+    public TResult _tryGetLast(out<Boolean> found) {
+        if (this.source._getCount() > this.minIndexInclusive) {
+            found.value = true;
+            return this.selector.apply(this.source.get(this.minIndexInclusive));
+        }
+
+        found.value = false;
+        return null;
+    }
+
+    private int getCount() {
+        int count = this.source._getCount();
+        if (count <= this.minIndexInclusive)
+            return 0;
+
+        return Math.min(count - 1, this.maxIndexInclusive) - this.minIndexInclusive + 1;
+    }
+
+    @Override
+    public TResult[] _toArray(Class<TResult> clazz) {
+        int count = this.getCount();
+        if (count == 0)
+            return ArrayUtils.empty(clazz);
+
+        TResult[] array = ArrayUtils.newInstance(clazz, count);
+        for (int i = 0, curIdx = Math.min(this.source._getCount() - 1, this.maxIndexInclusive); i != array.length; ++i, --curIdx)
+            array[i] = this.selector.apply(this.source.get(curIdx));
+
+        return array;
+    }
+
+    @Override
+    public Object[] _toArray() {
+        int count = this.getCount();
+        if (count == 0)
+            return ArrayUtils.empty();
+
+        Object[] array = new Object[count];
+        for (int i = 0, curIdx = Math.min(this.source._getCount() - 1, this.maxIndexInclusive); i != array.length; ++i, --curIdx)
+            array[i] = this.selector.apply(this.source.get(curIdx));
+
+        return array;
+    }
+
+    @Override
+    public List<TResult> _toList() {
+        int count = this.getCount();
+        if (count == 0)
+            return ListUtils.empty();
+
+        List<TResult> list = new ArrayList<>(count);
+        int end = this.minIndexInclusive - 1;
+        for (int i = Math.min(this.source._getCount() - 1, this.maxIndexInclusive); i != end; --i)
+            list.add(this.selector.apply(this.source.get(i)));
+
+        return list;
+    }
+
+    @Override
+    public int _getCount(boolean onlyIfCheap) {
+        // In case someone uses Count() to force evaluation of
+        // the selector, run it provided `onlyIfCheap` is false.
+        int count = this.getCount();
+
+        if (!onlyIfCheap) {
+            int end = this.minIndexInclusive - 1;
+            for (int i = Math.min(this.source._getCount() - 1, this.maxIndexInclusive); i != end; --i)
+                this.selector.apply(this.source.get(i));
+        }
+
+        return count;
+    }
+}
diff --git a/src/main/java/com/bestvike/linq/enumerable/_Partition.java b/src/main/java/com/bestvike/linq/enumerable/_Partition.java
index d007bd9b..fa60378e 100644
--- a/src/main/java/com/bestvike/linq/enumerable/_Partition.java
+++ b/src/main/java/com/bestvike/linq/enumerable/_Partition.java
@@ -196,7 +196,7 @@ public int _getCount(boolean onlyIfCheap) {
 
 
 @DebuggerDisplay("Count = {_getCount()}")
-final class ListPartition<TSource> extends Iterator<TSource> implements IPartition<TSource> {
+final class ListPartition<TSource> extends ReverseIterator<TSource> implements IPartition<TSource> {
     private final IArrayList<TSource> source;
     private final int minIndexInclusive;
     private final int maxIndexInclusive;
@@ -215,6 +215,11 @@ public Iterator<TSource> clone() {
         return new ListPartition<>(this.source, this.minIndexInclusive, this.maxIndexInclusive);
     }
 
+    @Override
+    public IEnumerable<TSource> _reverse() {
+        return new ReverseListPartition<>(this.source, this.minIndexInclusive, this.maxIndexInclusive);
+    }
+
     @Override
     public boolean moveNext() {
         // _state - 1 represents the zero-based index into the list.
@@ -337,7 +342,7 @@ public int _getCount(boolean onlyIfCheap) {
 
 
 @DebuggerDisplay("Count = {_getCount()}")
-final class IListPartition<TSource> extends Iterator<TSource> implements IPartition<TSource> {
+final class IListPartition<TSource> extends ReverseIterator<TSource> implements IPartition<TSource> {
     private final IList<TSource> source;
     private final int minIndexInclusive;
     private final int maxIndexInclusive;
@@ -387,6 +392,12 @@ public Iterator<TSource> clone() {
         return new IListPartition<>(this.source, this.minIndexInclusive, this.maxIndexInclusive);
     }
 
+    //see EnumerablePartition
+    @Override
+    public IEnumerable<TSource> _reverse() {
+        return new ReverseIListPartition<>(this.source, this.minIndexInclusive, this.maxIndexInclusive);
+    }
+
     //see EnumerablePartition
     @Override
     public void close() {
@@ -578,6 +589,306 @@ private boolean skipBeforeFirst(IEnumerator<TSource> en) {
 }
 
 
+final class ReverseListPartition<TSource> extends ReverseIterator<TSource> implements IPartition<TSource> {
+    private final IArrayList<TSource> source;
+    private final int minIndexInclusive;
+    private final int maxIndexInclusive;
+
+    ReverseListPartition(IArrayList<TSource> source, int minIndexInclusive, int maxIndexInclusive) {
+        assert source != null;
+        assert minIndexInclusive >= 0;
+        assert minIndexInclusive <= maxIndexInclusive;
+        this.source = source;
+        this.minIndexInclusive = minIndexInclusive;
+        this.maxIndexInclusive = maxIndexInclusive;
+    }
+
+    @Override
+    public Iterator<TSource> clone() {
+        return new ReverseListPartition<>(this.source, this.minIndexInclusive, this.maxIndexInclusive);
+    }
+
+    @Override
+    public IEnumerable<TSource> _reverse() {
+        return new ListPartition<>(this.source, this.minIndexInclusive, this.maxIndexInclusive);
+    }
+
+    @Override
+    public boolean moveNext() {
+        // _state - 1 represents the zero-based index into the list.
+        // Having a separate field for the index would be more readable. However, we save it
+        // into _state with a bias to minimize field size of the iterator.
+        int index = this.state - 1;
+        int count = this.source._getCount();
+        if (Integer.compareUnsigned(index, this.maxIndexInclusive - this.minIndexInclusive) <= 0 && index < count - this.minIndexInclusive) {
+            this.current = this.source.get(Math.min(count - 1, this.maxIndexInclusive) - index);
+            ++this.state;
+            return true;
+        }
+
+        this.close();
+        return false;
+    }
+
+    @Override
+    public <TResult> IEnumerable<TResult> _select(Func1<TSource, TResult> selector) {
+        return new SelectReverseListPartitionIterator<>(this.source, selector, this.minIndexInclusive, this.maxIndexInclusive);
+    }
+
+    @Override
+    public IPartition<TSource> _skip(int count) {
+        assert count > 0;
+        int maxIndex = Math.min(this.source._getCount() - 1, this.maxIndexInclusive) - count;
+        return maxIndex < this.minIndexInclusive ? EmptyPartition.instance() : new ReverseListPartition<>(this.source, this.minIndexInclusive, maxIndex);
+    }
+
+    @Override
+    public IPartition<TSource> _take(int count) {
+        assert count > 0;
+        int minIndex = Math.min(this.source._getCount() - 1, this.maxIndexInclusive) - count + 1;
+        return minIndex <= this.minIndexInclusive ? this : new ReverseListPartition<>(this.source, minIndex, this.maxIndexInclusive);
+    }
+
+    @Override
+    public TSource _tryGetElementAt(int index, out<Boolean> found) {
+        int count = this.source._getCount();
+        if (Integer.compareUnsigned(index, this.maxIndexInclusive - this.minIndexInclusive) <= 0 && index < count - this.minIndexInclusive) {
+            found.value = true;
+            return this.source.get(Math.min(count - 1, this.maxIndexInclusive) - index);
+        }
+
+        found.value = false;
+        return null;
+    }
+
+    @Override
+    public TSource _tryGetFirst(out<Boolean> found) {
+        int lastIndex = this.source._getCount() - 1;
+        if (lastIndex >= this.minIndexInclusive) {
+            found.value = true;
+            return this.source.get(Math.min(lastIndex, this.maxIndexInclusive));
+        }
+
+        found.value = false;
+        return null;
+    }
+
+    @Override
+    public TSource _tryGetLast(out<Boolean> found) {
+        if (this.source._getCount() > this.minIndexInclusive) {
+            found.value = true;
+            return this.source.get(this.minIndexInclusive);
+        }
+
+        found.value = false;
+        return null;
+    }
+
+    private int _getCount() {
+        int count = this.source._getCount();
+        if (count <= this.minIndexInclusive)
+            return 0;
+
+        return Math.min(count - 1, this.maxIndexInclusive) - this.minIndexInclusive + 1;
+    }
+
+    @Override
+    public TSource[] _toArray(Class<TSource> clazz) {
+        int count = this._getCount();
+        if (count == 0)
+            return ArrayUtils.empty(clazz);
+
+        TSource[] array = ArrayUtils.newInstance(clazz, count);
+        for (int i = 0, curIdx = Math.min(this.source._getCount() - 1, this.maxIndexInclusive); i != array.length; ++i, --curIdx)
+            array[i] = this.source.get(curIdx);
+
+        return array;
+    }
+
+    @Override
+    public Object[] _toArray() {
+        int count = this._getCount();
+        if (count == 0)
+            return ArrayUtils.empty();
+
+        Object[] array = new Object[count];
+        for (int i = 0, curIdx = Math.min(this.source._getCount() - 1, this.maxIndexInclusive); i != array.length; ++i, --curIdx)
+            array[i] = this.source.get(curIdx);
+
+        return array;
+    }
+
+    @Override
+    public List<TSource> _toList() {
+        int count = this._getCount();
+        if (count == 0)
+            return ListUtils.empty();
+
+        List<TSource> list = new ArrayList<>(count);
+        int end = this.minIndexInclusive - 1;
+        for (int i = Math.min(this.source._getCount() - 1, this.maxIndexInclusive); i != end; --i)
+            list.add(this.source.get(i));
+
+        return list;
+    }
+
+    @Override
+    public int _getCount(boolean onlyIfCheap) {
+        return this._getCount();
+    }
+}
+
+
+final class ReverseIListPartition<TSource> extends ReverseIterator<TSource> implements IPartition<TSource> {
+    private final IList<TSource> source;
+    private final int minIndexInclusive;
+    private final int maxIndexInclusive;
+
+    ReverseIListPartition(IList<TSource> source, int minIndexInclusive, int maxIndexInclusive) {
+        assert source != null;
+        assert minIndexInclusive >= 0;
+        assert minIndexInclusive <= maxIndexInclusive;
+        this.source = source;
+        this.minIndexInclusive = minIndexInclusive;
+        this.maxIndexInclusive = maxIndexInclusive;
+    }
+
+    @Override
+    public Iterator<TSource> clone() {
+        return new ReverseIListPartition<>(this.source, this.minIndexInclusive, this.maxIndexInclusive);
+    }
+
+    @Override
+    public IEnumerable<TSource> _reverse() {
+        return new IListPartition<>(this.source, this.minIndexInclusive, this.maxIndexInclusive);
+    }
+
+    @Override
+    public boolean moveNext() {
+        // _state - 1 represents the zero-based index into the list.
+        // Having a separate field for the index would be more readable. However, we save it
+        // into _state with a bias to minimize field size of the iterator.
+        int index = this.state - 1;
+        int count = this.source._getCount();
+        if (Integer.compareUnsigned(index, this.maxIndexInclusive - this.minIndexInclusive) <= 0 && index < count - this.minIndexInclusive) {
+            this.current = this.source.get(Math.min(count - 1, this.maxIndexInclusive) - index);
+            ++this.state;
+            return true;
+        }
+
+        this.close();
+        return false;
+    }
+
+    @Override
+    public <TResult> IEnumerable<TResult> _select(Func1<TSource, TResult> selector) {
+        return new SelectReverseIListPartitionIterator<>(this.source, selector, this.minIndexInclusive, this.maxIndexInclusive);
+    }
+
+    @Override
+    public IPartition<TSource> _skip(int count) {
+        assert count > 0;
+        int maxIndex = Math.min(this.source._getCount() - 1, this.maxIndexInclusive) - count;
+        return maxIndex < this.minIndexInclusive ? EmptyPartition.instance() : new ReverseIListPartition<>(this.source, this.minIndexInclusive, maxIndex);
+    }
+
+    @Override
+    public IPartition<TSource> _take(int count) {
+        assert count > 0;
+        int minIndex = Math.min(this.source._getCount() - 1, this.maxIndexInclusive) - count + 1;
+        return minIndex <= this.minIndexInclusive ? this : new ReverseIListPartition<>(this.source, minIndex, this.maxIndexInclusive);
+    }
+
+    @Override
+    public TSource _tryGetElementAt(int index, out<Boolean> found) {
+        int count = this.source._getCount();
+        if (Integer.compareUnsigned(index, this.maxIndexInclusive - this.minIndexInclusive) <= 0 && index < count - this.minIndexInclusive) {
+            found.value = true;
+            return this.source.get(Math.min(count - 1, this.maxIndexInclusive) - index);
+        }
+
+        found.value = false;
+        return null;
+    }
+
+    @Override
+    public TSource _tryGetFirst(out<Boolean> found) {
+        int lastIndex = this.source._getCount() - 1;
+        if (lastIndex >= this.minIndexInclusive) {
+            found.value = true;
+            return this.source.get(Math.min(lastIndex, this.maxIndexInclusive));
+        }
+
+        found.value = false;
+        return null;
+    }
+
+    @Override
+    public TSource _tryGetLast(out<Boolean> found) {
+        if (this.source._getCount() > this.minIndexInclusive) {
+            found.value = true;
+            return this.source.get(this.minIndexInclusive);
+        }
+
+        found.value = false;
+        return null;
+    }
+
+    private int _getCount() {
+        int count = this.source._getCount();
+        if (count <= this.minIndexInclusive)
+            return 0;
+
+        return Math.min(count - 1, this.maxIndexInclusive) - this.minIndexInclusive + 1;
+    }
+
+    @Override
+    public TSource[] _toArray(Class<TSource> clazz) {
+        int count = this._getCount();
+        if (count == 0)
+            return ArrayUtils.empty(clazz);
+
+        TSource[] array = ArrayUtils.newInstance(clazz, count);
+        for (int i = 0, curIdx = Math.min(this.source._getCount() - 1, this.maxIndexInclusive); i != array.length; ++i, --curIdx)
+            array[i] = this.source.get(curIdx);
+
+        return array;
+    }
+
+    @Override
+    public Object[] _toArray() {
+        int count = this._getCount();
+        if (count == 0)
+            return ArrayUtils.empty();
+
+        Object[] array = new Object[count];
+        for (int i = 0, curIdx = Math.min(this.source._getCount() - 1, this.maxIndexInclusive); i != array.length; ++i, --curIdx)
+            array[i] = this.source.get(curIdx);
+
+        return array;
+    }
+
+    @Override
+    public List<TSource> _toList() {
+        int count = this._getCount();
+        if (count == 0)
+            return ListUtils.empty();
+
+        List<TSource> list = new ArrayList<>(count);
+        int end = this.minIndexInclusive - 1;
+        for (int i = Math.min(this.source._getCount() - 1, this.maxIndexInclusive); i != end; --i)
+            list.add(this.source.get(i));
+
+        return list;
+    }
+
+    @Override
+    public int _getCount(boolean onlyIfCheap) {
+        return this._getCount();
+    }
+}
+
+
 final class EnumerablePartition<TSource> extends Iterator<TSource> implements IPartition<TSource> {
     private final IEnumerable<TSource> source;
     private final int minIndexInclusive;// -1 if we want everything past _minIndexInclusive.
