lib/standard/array: add `Array::sub`
[nit.git] / lib / standard / collection / array.nit
index 253dd9e..cdb5242 100644 (file)
@@ -13,7 +13,9 @@
 
 # This module introduces the standard array structure.
 # It also implements two other abstract collections : ArrayMap and ArraySet
-module array
+module array is
+       no_warning "useless-type-test" # to avoid warning with nitc while compiling with c_src
+end
 
 import abstract_collection
 
@@ -130,8 +132,70 @@ abstract class AbstractArrayRead[E]
                end
        end
 
-       redef fun iterator: ArrayIterator[E] do return new ArrayIterator[E](self)
+       redef fun iterator: ArrayIterator[E] do
+               var res = _free_iterator
+               if res == null then return new ArrayIterator[E](self)
+               res._index = 0
+               _free_iterator = null
+               return res
+       end
+
+       # An old iterator, free to reuse.
+       # Once an iterator is `finish`, it become reusable.
+       # Since some arrays are iterated a lot, this avoid most of the
+       # continuous allocation/garbage-collection of the needed iterators.
+       private var free_iterator: nullable ArrayIterator[E] = null
+
        redef fun reverse_iterator do return new ArrayReverseIterator[E](self)
+
+       # Returns a sub-array containing `count` elements starting from `from`.
+       #
+       # For most cases (see other case bellow),
+       # the first element is `from` and
+       # the last element is `from+count-1`.
+       #
+       # ~~~
+       # var a = [10, 20, 30, 40, 50]
+       # assert a.sub(0, 3) == [10, 20, 30]
+       # assert a.sub(3, 2) == [40, 50]
+       # assert a.sub(3, 1) == [40]
+       # ~~~
+       #
+       # If `count` is 0 or negative then an empty array is returned
+       #
+       # ~~~
+       # assert a.sub(3,0).is_empty
+       # assert a.sub(3,-1).is_empty
+       # ~~~
+       #
+       # If `from < 0` or `from+count>length` then inexistent elements are ignored.
+       # In this case the length of the result is lower than count.
+       #
+       # ~~~
+       # assert a.sub(-2, 4)  == [10, 20]
+       # assert a.sub(4, 99)  == [50]
+       # assert a.sub(-9, 99) == [10,20,30,40,50]
+       # assert a.sub(-99, 9).is_empty
+       # ~~~
+       fun sub(from: Int, count: Int): Array[E] do
+               if from < 0 then
+                       count += from
+                       from = 0
+               end
+               if count < 0 then
+                       count = 0
+               end
+               var to = from + count
+               if to > length then
+                       to = length
+               end
+               var res = new Array[E].with_capacity(to - from)
+               while from < to do
+                       res.add(self[from])
+                       from += 1
+               end
+               return res
+       end
 end
 
 # Resizable one dimension array of objects.
@@ -477,6 +541,8 @@ private class ArrayIterator[E]
        redef var index = 0
 
        var array: AbstractArrayRead[E]
+
+       redef fun finish do _array._free_iterator = self
 end
 
 private class ArrayReverseIterator[E]